Files
cordova-imagePicker/src/ios/GMImagePicker/mrprogress/Components/MRNavigationBarProgressView.m
T

255 lines
7.9 KiB
Objective-C
Executable File

//
// MRNavigationBarProgressView.m
// MRNavigationBarProgressView
//
// Created by Marius Rackwitz on 09.10.13.
// Copyright (c) 2013 Marius Rackwitz. All rights reserved.
//
#import "MRNavigationBarProgressView.h"
#import <objc/runtime.h>
static NSString *const MR_UINavigationControllerDidShowViewControllerNotification = @"UINavigationControllerDidShowViewControllerNotification";
static NSString *const MR_UINavigationControllerLastVisibleViewController = @"UINavigationControllerLastVisibleViewController";
@interface UINavigationController (NavigationBarProgressView_Private)
@property (nonatomic, weak) MRNavigationBarProgressView *progressView;
@end
@implementation UINavigationController (NavigationBarProgressView_Private)
- (void)setProgressView:(MRNavigationBarProgressView *)progressView {
objc_setAssociatedObject(self, @selector(progressView), progressView, OBJC_ASSOCIATION_ASSIGN);
}
- (MRNavigationBarProgressView *)progressView {
return objc_getAssociatedObject(self, @selector(progressView));
}
@end
@interface MRNavigationBarProgressView ()
@property (nonatomic, weak, readwrite) UIView *progressView;
@property (nonatomic, weak, readwrite) UIViewController *viewController;
@property (nonatomic, weak, readwrite) UIView *barView;
@end
@implementation MRNavigationBarProgressView
@dynamic progress;
static NSNumberFormatter *progressNumberFormatter;
+ (void)initialize {
NSNumberFormatter *numberFormatter = [NSNumberFormatter new];
numberFormatter.numberStyle = NSNumberFormatterPercentStyle;
numberFormatter.locale = NSLocale.currentLocale;
progressNumberFormatter = numberFormatter;
}
+ (instancetype)progressViewForNavigationController:(UINavigationController *)navigationController {
// Try to get existing bar
MRNavigationBarProgressView *progressView = navigationController.progressView;
if (progressView) {
return progressView;
}
// Create new bar
UINavigationBar *navigationBar = navigationController.navigationBar;
progressView = [MRNavigationBarProgressView new];
progressView.barView = navigationBar;
progressView.progressTintColor = navigationBar.tintColor
? navigationBar.tintColor : UIApplication.sharedApplication.delegate.window.tintColor;
// Store bar and add to view hierachy
navigationController.progressView = progressView;
[navigationController.navigationBar addSubview:progressView];
// Observe topItem
progressView.viewController = navigationController.topViewController;
[progressView registerObserverForNavigationController:navigationController];
return progressView;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
+ (BOOL)requiresConstraintBasedLayout {
return YES;
}
- (void)commonInit {
self.isAccessibilityElement = YES;
self.accessibilityLabel = NSLocalizedString(@"Determinate Progress", @"Accessibility label for navigation bar progress view");
self.accessibilityTraits = UIAccessibilityTraitUpdatesFrequently;
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.opaque = NO;
UIView *progressView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, self.bounds.size.height)];
progressView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;
progressView.backgroundColor = self.tintColor;
[self addSubview:progressView];
self.progressView = progressView;
self.progress = 0;
[self tintColorDidChange];
}
- (void)registerObserverForNavigationController:(UINavigationController *)navigationController {
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(navigationControllerDidShowViewController:)
name:MR_UINavigationControllerDidShowViewControllerNotification
object:navigationController];
}
- (void)unregisterObserverForNavigationController:(UINavigationController *)navigationController {
[NSNotificationCenter.defaultCenter removeObserver:self];
}
- (void)navigationControllerDidShowViewController:(NSNotification *)notification {
UINavigationController *navigationController = notification.object;
UIViewController *lastVisibleVC = notification.userInfo[MR_UINavigationControllerLastVisibleViewController];
// Check if our controller will be still the topViewController or was popped
if (lastVisibleVC == self.viewController) {
// Unregister observer
[self unregisterObserverForNavigationController:navigationController];
// Remove reference
navigationController.progressView = nil;
// Remove receiver from view hierachy
[self removeFromSuperview];
}
}
- (void) dealloc {
[NSNotificationCenter.defaultCenter removeObserver:self];
}
- (void)setBarView:(UIView *)barView {
_barView = barView;
[self layoutSubviews];
}
#pragma mark - Layout
- (void)layoutSubviews {
[super layoutSubviews];
CGRect barFrame = self.barView.frame;
const CGFloat progressBarHeight = 2;
CGRect frame = CGRectMake(barFrame.origin.x,
0,
barFrame.size.width,
progressBarHeight);
if ([self.barView isKindOfClass:UINavigationBar.class]) {
const CGFloat barBorderHeight = 0.5;
frame.origin.y = barFrame.size.height - progressBarHeight + barBorderHeight;
}
if (!CGRectEqualToRect(self.frame, frame)) {
self.frame = frame;
}
[self layoutProgressView];
}
- (void)layoutProgressView {
self.progressView.frame = CGRectMake(0, 0, self.frame.size.width * self.progress, self.frame.size.height);
}
#pragma mark - Getter and setter for progress tint color
- (void)setProgressTintColor:(UIColor *)tintColor {
self.progressView.backgroundColor = tintColor;
}
- (UIColor *)progressTintColor {
return self.progressView.backgroundColor;
}
#pragma mark - Control progress
- (void)setProgress:(float)progress {
assert(progress >= 0 && progress <= 1);
[self _setProgress:progress];
}
- (void)_setProgress:(float)progress {
_progress = progress;
[self progressDidChange];
}
- (void)progressDidChange {
self.progressView.alpha = self.progress >= 1 ? 0 : 1;
[self layoutProgressView];
self.accessibilityValue = [progressNumberFormatter stringFromNumber:@(self.progress)];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self);
}
- (void)setProgress:(float)progress animated:(BOOL)animated {
if (animated) {
if (progress > 0 && progress < 1.0 && self.progressView.alpha <= CGFLOAT_MIN) {
// progressView was hidden. Make it visible first.
self.progressView.alpha = 1;
}
void(^completion)(BOOL) = ^(BOOL finished){
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.progressView.alpha = self.progress >= 1 ? 0 : 1;
} completion:nil];
};
if (progress > self.progress || self.progress >= 1) {
// Progress increased: ease out.
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self _setProgress:progress];
} completion:completion];
} else {
// Progress decreased: bounce.
[UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:0 options:0 animations:^{
[self _setProgress:progress];
} completion:completion];
}
} else {
self.progress = progress;
}
}
@end