From 7b02207537d35bfa1714bf8beafc921f717d100a Mon Sep 17 00:00:00 2001 From: 单军华 Date: Wed, 11 Jul 2018 10:47:42 +0800 Subject: [PATCH] 首次上传 --- screendisplay/Pods/M13ProgressSuite/Classes/NavigationController/UINavigationController+M13ProgressViewBar.m | 542 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 542 insertions(+), 0 deletions(-) diff --git a/screendisplay/Pods/M13ProgressSuite/Classes/NavigationController/UINavigationController+M13ProgressViewBar.m b/screendisplay/Pods/M13ProgressSuite/Classes/NavigationController/UINavigationController+M13ProgressViewBar.m new file mode 100755 index 0000000..ba0e7fd --- /dev/null +++ b/screendisplay/Pods/M13ProgressSuite/Classes/NavigationController/UINavigationController+M13ProgressViewBar.m @@ -0,0 +1,542 @@ +// +// UINavigationController+M13ProgressViewBar.m +// M13ProgressView +// + +#import "UINavigationController+M13ProgressViewBar.h" +#import "UIApplication+M13ProgressSuite.h" +#import <objc/runtime.h> + +//Keys to set properties since one cannot define properties in a category. +static char oldTitleKey; +static char displayLinkKey; +static char animationFromKey; +static char animationToKey; +static char animationStartTimeKey; +static char progressKey; +static char progressViewKey; +static char indeterminateKey; +static char indeterminateLayerKey; +static char isShowingProgressKey; +static char primaryColorKey; +static char secondaryColorKey; +static char backgroundColorKey; +static char backgroundViewKey; + +@implementation UINavigationController (M13ProgressViewBar) + +#pragma mark Title + +- (void)setProgressTitle:(NSString *)title +{ + //Change the title on screen. + NSString *oldTitle = [self getOldTitle]; + if (oldTitle == nil) { + //We haven't changed the navigation bar yet. So store the original before changing it. + [self setOldTitle:self.visibleViewController.navigationItem.title]; + } + + if (title != nil) { + self.visibleViewController.navigationItem.title = title; + } else { + self.visibleViewController.navigationItem.title = oldTitle; + [self setOldTitle:nil]; + } +} + +#pragma mark Progress + +- (void)setProgress:(CGFloat)progress animated:(BOOL)animated +{ + CADisplayLink *displayLink = [self getDisplayLink]; + if (animated == NO) { + if (displayLink) { + //Kill running animations + [displayLink invalidate]; + [self setDisplayLink:nil]; + } + [self setProgress:progress]; + } else { + [self setAnimationStartTime:CACurrentMediaTime()]; + [self setAnimationFromValue:[self getProgress]]; + [self setAnimationToValue:progress]; + if (!displayLink) { + //Create and setup the display link + [displayLink invalidate]; + displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(animateProgress:)]; + [self setDisplayLink:displayLink]; + [displayLink addToRunLoop:NSRunLoop.mainRunLoop forMode:NSRunLoopCommonModes]; + } /*else { + //Reuse the current display link + }*/ + } +} + +- (void)animateProgress:(CADisplayLink *)displayLink +{ + dispatch_async(dispatch_get_main_queue(), ^{ + CGFloat dt = (displayLink.timestamp - [self getAnimationStartTime]) / [self getAnimationDuration]; + if (dt >= 1.0) { + //Order is important! Otherwise concurrency will cause errors, because setProgress: will detect an animation in progress and try to stop it by itself. Once over one, set to actual progress amount. Animation is over. + [displayLink invalidate]; + [self setDisplayLink:nil]; + [self setProgress:[self getAnimationToValue]]; + return; + } + + //Set progress + [self setProgress:[self getAnimationFromValue] + dt * ([self getAnimationToValue] - [self getAnimationFromValue])]; + + }); +} + +- (void)finishProgress +{ + UIView *progressView = [self getProgressView]; + UIView *backgroundView = [self getBackgroundView]; + if (progressView && backgroundView) { + dispatch_async(dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:0.1 animations:^{ + CGRect progressFrame = progressView.frame; + progressFrame.size.width = self.navigationBar.frame.size.width; + progressView.frame = progressFrame; + } completion:^(BOOL finished) { + [UIView animateWithDuration:0.5 animations:^{ + progressView.alpha = 0; + backgroundView.alpha = 0; + } completion:^(BOOL finished) { + [progressView removeFromSuperview]; + [backgroundView removeFromSuperview]; + backgroundView.alpha = 1; + progressView.alpha = 1; + [self setTitle:nil]; + [self setIsShowingProgressBar:NO]; + }]; + }]; + }); + } +} + +- (void)cancelProgress +{ + UIView *progressView = [self getProgressView]; + UIView *backgroundView = [self getBackgroundView]; + + if (progressView && backgroundView) { + dispatch_async(dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:0.5 animations:^{ + progressView.alpha = 0; + backgroundView.alpha = 0; + } completion:^(BOOL finished) { + [progressView removeFromSuperview]; + [backgroundView removeFromSuperview]; + progressView.alpha = 1; + backgroundView.alpha = 1; + [self setTitle:nil]; + [self setIsShowingProgressBar:NO]; + }]; + }); + } +} + +#pragma mark Orientation + +- (UIInterfaceOrientation)currentDeviceOrientation +{ + UIInterfaceOrientation orientation; + + if ([UIApplication isM13AppExtension]) { + if ([UIScreen mainScreen].bounds.size.width < [UIScreen mainScreen].bounds.size.height) { + orientation = UIInterfaceOrientationPortrait; + } else { + orientation = UIInterfaceOrientationLandscapeLeft; + } + } else { + orientation = [UIApplication safeM13SharedApplication].statusBarOrientation; + } + + return orientation; +} + +#pragma mark Drawing + +- (void)showProgress +{ + UIView *progressView = [self getProgressView]; + UIView *backgroundView = [self getBackgroundView]; + + [UIView animateWithDuration:.1 animations:^{ + progressView.alpha = 1; + backgroundView.alpha = 1; + }]; + + [self setIsShowingProgressBar:YES]; +} + +- (void)updateProgress +{ + [self updateProgressWithInterfaceOrientation:[self currentDeviceOrientation]]; +} + +- (void)updateProgressWithInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + //Create the progress view if it doesn't exist + UIView *progressView = [self getProgressView]; + if(!progressView) + { + progressView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 2.5)]; + progressView.clipsToBounds = YES; + [self setProgressView:progressView]; + } + + if ([self getPrimaryColor]) { + progressView.backgroundColor = [self getPrimaryColor]; + } else { + progressView.backgroundColor = self.navigationBar.tintColor; + } + + //Create background view if it doesn't exist + UIView *backgroundView = [self getBackgroundView]; + if (!backgroundView) + { + backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 2.5)]; + backgroundView.clipsToBounds = YES; + [self setBackgroundView:backgroundView]; + } + + if ([self getBackgroundColor]) { + backgroundView.backgroundColor = [self getBackgroundColor]; + } else { + backgroundView.backgroundColor = [UIColor clearColor]; + } + + //Calculate the frame of the navigation bar, based off the orientation. + UIView *topView = self.topViewController.view; + CGSize screenSize; + if (topView) { + screenSize = topView.bounds.size; + } else { + screenSize = [UIScreen mainScreen].bounds.size; + } + CGFloat width = 0.0; + CGFloat height = 0.0; + //Calculate the width of the screen + if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) { + //Use the maximum value + width = MAX(screenSize.width, screenSize.height); + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) { + height = 32.0; //Hate hardcoding values, but autolayout doesn't work, and cant retreive the new height until after the animation completes. + } else { + height = 44.0; //Hate hardcoding values, but autolayout doesn't work, and cant retreive the new height until after the animation completes. + } + } else { + //Use the minimum value + width = MIN(screenSize.width, screenSize.height); + height = 44.0; //Hate hardcoding values, but autolayout doesn't work, and cant retreive the new height until after the animation completes. + } + + //Check if the progress view is in its superview and if we are showing the bar. + if (progressView.superview == nil && [self isShowingProgressBar]) { + [self.navigationBar addSubview:backgroundView]; + [self.navigationBar addSubview:progressView]; + } + + //Layout + if (![self getIndeterminate]) { + //Calculate the width of the progress view; + float progressWidth = (float)width * (float)[self getProgress]; + //Set the frame of the progress view + progressView.frame = CGRectMake(0, height - 2.5, progressWidth, 2.5); + } else { + //Calculate the width of the progress view + progressView.frame = CGRectMake(0, height - 2.5, width, 2.5); + } + backgroundView.frame = CGRectMake(0, height - 2.5, width, 2.5); +} + +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration +{ + [self updateProgressWithInterfaceOrientation:toInterfaceOrientation]; + [self drawIndeterminateWithInterfaceOrientation:toInterfaceOrientation]; +} + +- (void)drawIndeterminate +{ + [self drawIndeterminateWithInterfaceOrientation:[self currentDeviceOrientation]]; +} + +- (void)drawIndeterminateWithInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + if ([self getIndeterminate]) { + //Get the indeterminate layer + CALayer *indeterminateLayer = [self getIndeterminateLayer]; + if (!indeterminateLayer) { + //Create if needed + indeterminateLayer = [CALayer layer]; + [self setIndeterminateLayer:indeterminateLayer]; + } + + //Calculate the frame of the navigation bar, based off the orientation. + CGSize screenSize = [UIScreen mainScreen].bounds.size; + CGFloat width = 0.0; + //Calculate the width of the screen + if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) { + //Use the maximum value + width = MAX(screenSize.width, screenSize.height); + } else { + //Use the minimum value + width = MIN(screenSize.width, screenSize.height); + } + + //Create the pattern image + CGFloat stripeWidth = 2.5; + //Start the image context + UIGraphicsBeginImageContextWithOptions(CGSizeMake(stripeWidth * 4.0, stripeWidth * 4.0), NO, [UIScreen mainScreen].scale); + //Fill the background + if ([self getPrimaryColor]) { + [[self getPrimaryColor] setFill]; + } else { + [self.navigationBar.tintColor setFill]; + } + UIBezierPath *fillPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, stripeWidth * 4.0, stripeWidth * 4.0)]; + [fillPath fill]; + //Draw the stripes + //Set the stripe color + if ([self getSecondaryColor]) { + [[self getSecondaryColor] setFill]; + } else { + CGFloat red; + CGFloat green; + CGFloat blue; + CGFloat alpha; + [self.navigationBar.barTintColor getRed:&red green:&green blue:&blue alpha:&alpha]; + //System set the tint color to a close to, but not non-zero value for each component. + if (alpha > .05) { + [self.navigationBar.barTintColor setFill]; + } else { + [[UIColor whiteColor] setFill]; + } + + } + + for (int i = 0; i < 4; i++) { + //Create the four inital points of the fill shape + CGPoint bottomLeft = CGPointMake(-(stripeWidth * 4.0), stripeWidth * 4.0); + CGPoint topLeft = CGPointMake(0, 0); + CGPoint topRight = CGPointMake(stripeWidth, 0); + CGPoint bottomRight = CGPointMake(-(stripeWidth * 4.0) + stripeWidth, stripeWidth * 4.0); + //Shift all four points as needed to draw all four stripes + bottomLeft.x += i * (2 * stripeWidth); + topLeft.x += i * (2 * stripeWidth); + topRight.x += i * (2 * stripeWidth); + bottomRight.x += i * (2 * stripeWidth); + //Create the fill path + UIBezierPath *path = [UIBezierPath bezierPath]; + [path moveToPoint:bottomLeft]; + [path addLineToPoint:topLeft]; + [path addLineToPoint:topRight]; + [path addLineToPoint:bottomRight]; + [path closePath]; + [path fill]; + } + //Retreive the image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + //Set the background of the progress layer + indeterminateLayer.backgroundColor = [UIColor colorWithPatternImage:image].CGColor; + + //remove any indeterminate layer animations + [indeterminateLayer removeAllAnimations]; + //Set the indeterminate layer frame and add to the sub view + indeterminateLayer.frame = CGRectMake(0, 0, width + (4 * 2.5), 2.5); + UIView *progressView = [self getProgressView]; + [progressView.layer addSublayer:indeterminateLayer]; + //Add the animation + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; + animation.duration = .1; + animation.repeatCount = HUGE_VALF; + animation.removedOnCompletion = YES; + animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(- (2 * 2.5) + (width / 2.0), 2.5 / 2.0)]; + animation.toValue = [NSValue valueWithCGPoint:CGPointMake(0 + (width / 2.0), 2.5 / 2.0)]; + [indeterminateLayer addAnimation:animation forKey:@"position"]; + } else { + CALayer *indeterminateLayer = [self getIndeterminateLayer]; + [indeterminateLayer removeAllAnimations]; + [indeterminateLayer removeFromSuperlayer]; + } +} + +#pragma mark properties + +- (void)setOldTitle:(NSString *)oldTitle +{ + objc_setAssociatedObject(self, &oldTitleKey, self.visibleViewController.navigationItem.title, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (NSString *)getOldTitle +{ + return objc_getAssociatedObject(self, &oldTitleKey); +} + +- (void)setDisplayLink:(CADisplayLink *)displayLink +{ + objc_setAssociatedObject(self, &displayLinkKey, displayLink, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (CADisplayLink *)getDisplayLink +{ + return objc_getAssociatedObject(self, &displayLinkKey); +} + +- (void)setAnimationFromValue:(CGFloat)animationFromValue +{ + objc_setAssociatedObject(self, &animationFromKey, [NSNumber numberWithFloat:(float)animationFromValue], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (CGFloat)getAnimationFromValue +{ + NSNumber *number = objc_getAssociatedObject(self, &animationFromKey); + return number.floatValue; +} + +- (void)setAnimationToValue:(CGFloat)animationToValue +{ + objc_setAssociatedObject(self, &animationToKey, [NSNumber numberWithFloat:(float)animationToValue], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (CGFloat)getAnimationToValue +{ + NSNumber *number = objc_getAssociatedObject(self, &animationToKey); + return number.floatValue; +} + +- (void)setAnimationStartTime:(NSTimeInterval)animationStartTime +{ + objc_setAssociatedObject(self, &animationStartTimeKey, [NSNumber numberWithFloat:(float)animationStartTime], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (NSTimeInterval)getAnimationStartTime +{ + NSNumber *number = objc_getAssociatedObject(self, &animationStartTimeKey); + return number.floatValue; +} + +- (void)setProgress:(CGFloat)progress +{ + if (progress > 1.0) { + progress = 1.0; + } else if (progress < 0.0) { + progress = 0.0; + } + objc_setAssociatedObject(self, &progressKey, [NSNumber numberWithFloat:(float)progress], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + //Draw the update + if ([NSThread isMainThread]) { + [self updateProgress]; + } else { + //Sometimes UINavigationController runs in a background thread. And drawing is not thread safe. + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateProgress]; + }); + } +} + +- (void)setIsShowingProgressBar:(BOOL)isShowingProgressBar +{ + objc_setAssociatedObject(self, &isShowingProgressKey, [NSNumber numberWithBool:isShowingProgressBar], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (CGFloat)getProgress +{ + NSNumber *number = objc_getAssociatedObject(self, &progressKey); + return number.floatValue; +} + +- (CGFloat)getAnimationDuration +{ + return .3; +} + +- (void)setProgressView:(UIView *)view +{ + objc_setAssociatedObject(self, &progressViewKey, view, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIView *)getProgressView +{ + return objc_getAssociatedObject(self, &progressViewKey); +} + +- (void)setBackgroundView:(UIView *)view +{ + objc_setAssociatedObject(self, &backgroundViewKey, view, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIView *)getBackgroundView +{ + return objc_getAssociatedObject(self, &backgroundViewKey); +} + + +- (void)setIndeterminate:(BOOL)indeterminate +{ + objc_setAssociatedObject(self, &indeterminateKey, [NSNumber numberWithBool:indeterminate], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + [self updateProgress]; + [self drawIndeterminate]; +} + +- (BOOL)getIndeterminate +{ + NSNumber *number = objc_getAssociatedObject(self, &indeterminateKey); + return number.boolValue; +} + +- (void)setIndeterminateLayer:(CALayer *)indeterminateLayer +{ + objc_setAssociatedObject(self, &indeterminateLayerKey, indeterminateLayer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (CALayer *)getIndeterminateLayer +{ + return objc_getAssociatedObject(self, &indeterminateLayerKey); +} + +- (BOOL)isShowingProgressBar +{ + return [objc_getAssociatedObject(self, &isShowingProgressKey) boolValue]; +} + +- (void)setPrimaryColor:(UIColor *)primaryColor +{ + objc_setAssociatedObject(self, &primaryColorKey, primaryColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + [self getProgressView].backgroundColor = primaryColor; + [self setIndeterminate:[self getIndeterminate]]; +} + +- (UIColor *)getPrimaryColor +{ + return objc_getAssociatedObject(self, &primaryColorKey); +} + +- (void)setSecondaryColor:(UIColor *)secondaryColor +{ + objc_setAssociatedObject(self, &secondaryColorKey, secondaryColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + [self setIndeterminate:[self getIndeterminate]]; +} + +- (UIColor *)getSecondaryColor +{ + return objc_getAssociatedObject(self, &secondaryColorKey); +} + +- (void)setBackgroundColor:(UIColor *)backgroundColor +{ + objc_setAssociatedObject(self, &backgroundColorKey, backgroundColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + [self setIndeterminate:[self getIndeterminate]]; +} + +- (UIColor *)getBackgroundColor +{ + return objc_getAssociatedObject(self, &backgroundColorKey); +} + +@end -- Gitblit v1.8.0