diff --git a/KVNProgress/Classes/KVNProgress.m b/KVNProgress/Classes/KVNProgress.m
index 1412b52..2409c03 100644
--- a/KVNProgress/Classes/KVNProgress.m
+++ b/KVNProgress/Classes/KVNProgress.m
@@ -21,17 +21,17 @@
#define KVNRadiansToDegress(radians) ((radians) * (180.0 / M_PI))
typedef NS_ENUM(NSUInteger, KVNProgressStyle) {
- KVNProgressStyleHidden,
- KVNProgressStyleProgress,
- KVNProgressStyleSuccess,
- KVNProgressStyleError
+ KVNProgressStyleHidden,
+ KVNProgressStyleProgress,
+ KVNProgressStyleSuccess,
+ KVNProgressStyleError
};
typedef NS_ENUM(NSUInteger, KVNProgressState) {
- KVNProgressStateHidden,
- KVNProgressStateAppearing,
- KVNProgressStateShowed,
- KVNProgressStateDismissing
+ KVNProgressStateHidden,
+ KVNProgressStateAppearing,
+ KVNProgressStateShowed,
+ KVNProgressStateDismissing
};
static CGFloat const KVNFadeAnimationDuration = 0.3f;
@@ -55,6 +55,11 @@ typedef NS_ENUM(NSUInteger, KVNProgressState) {
@interface KVNProgress ()
+// Dispatch
+@property (nonatomic) dispatch_queue_t queue;
+@property (nonatomic) dispatch_semaphore_t semaphore;
+
+// Configuration
@property (nonatomic) CGFloat progress;
@property (nonatomic) KVNProgressBackgroundType backgroundType;
@property (nonatomic) NSString *status;
@@ -62,7 +67,6 @@ @interface KVNProgress ()
@property (nonatomic) KVNProgressConfiguration *configuration;
@property (nonatomic) NSDate *showActionTrigerredDate;
@property (nonatomic, getter = isFullScreen) BOOL fullScreen;
-@property (nonatomic, getter = isWaitingToChangeHUD) BOOL waitingToChangeHUD;
@property (nonatomic) KVNProgressState state;
// UI
@@ -87,6 +91,8 @@ @interface KVNProgress ()
@property (nonatomic) NSArray *constraintsToSuperview;
++ (void)synchronousDismissWithCompletion:(KVNCompletionBlock)completion;
+
@end
@implementation KVNProgress
@@ -95,1179 +101,1217 @@ @implementation KVNProgress
+ (KVNProgress *)sharedView
{
- static KVNProgress *sharedView = nil;
- static dispatch_once_t onceToken;
-
- dispatch_once(&onceToken, ^{
- UINib *nib = [UINib nibWithNibName:@"KVNProgressView"
+ static KVNProgress *sharedView = nil;
+ static dispatch_once_t onceToken;
+
+ dispatch_once(&onceToken, ^{
+ UINib *nib = [UINib nibWithNibName:@"KVNProgressView"
bundle:[NSBundle bundleForClass:[self class]]];
- NSArray *nibViews = [nib instantiateWithOwner:self
- options:0];
-
- sharedView = nibViews[0];
- });
-
- return sharedView;
+ NSArray *nibViews = [nib instantiateWithOwner:self
+ options:0];
+
+ sharedView = nibViews[0];
+ });
+
+ return sharedView;
}
#pragma mark - Life cycle
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
- if (self = [super initWithCoder:aDecoder]) {
- if (!configuration) {
- configuration = [KVNProgressConfiguration defaultConfiguration];
- }
-
- _configuration = configuration;
-
- [self registerForNotifications];
- }
-
- return self;
+ if (self = [super initWithCoder:aDecoder]) {
+ self.queue = dispatch_queue_create("KVNProgressDispatch", NULL);
+ self.semaphore = dispatch_semaphore_create(0);
+
+ if (!configuration) {
+ configuration = [KVNProgressConfiguration defaultConfiguration];
+ }
+
+ _configuration = configuration;
+
+ [self registerForNotifications];
+ }
+
+ return self;
}
- (void)dealloc
{
- [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Notifications
- (void)registerForNotifications {
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(orientationDidChange:)
- name:UIDeviceOrientationDidChangeNotification
- object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(orientationDidChange:)
+ name:UIDeviceOrientationDidChangeNotification
+ object:nil];
}
- (void)orientationDidChange:(NSNotification *)notification {
- if (![self.class isVisible]) {
- return;
- }
-
- if ([self.superview isKindOfClass:[UIWindow class]]) {
- KVNPrepareBlockSelf();
- [UIView animateWithDuration:0.3f
- animations:^{
- [KVNBlockSelf updateUIForOrientation];
- }];
- } else {
- [self updateUIForOrientation];
- }
+ if (![self.class isVisible]) {
+ return;
+ }
+
+ if ([self.superview isKindOfClass:[UIWindow class]]) {
+ KVNPrepareBlockSelf();
+ [UIView animateWithDuration:0.3f
+ animations:^{
+ [KVNBlockSelf updateUIForOrientation];
+ }];
+ } else {
+ [self updateUIForOrientation];
+ }
}
#pragma mark - Loading
+ (void)show
{
- [self showWithStatus:nil];
+ [self showWithStatus:nil];
}
+ (void)showWithStatus:(NSString *)status
{
- [self showWithStatus:status
- onView:nil];
+ [self showWithStatus:status
+ onView:nil];
}
+ (void)showWithStatus:(NSString *)status
- onView:(UIView *)superview
+ onView:(UIView *)superview
{
- [self showHUDWithProgress:KVNProgressIndeterminate
- style:KVNProgressStyleProgress
- status:status
- superview:superview
- completion:nil];
+ [self showHUDWithProgress:KVNProgressIndeterminate
+ style:KVNProgressStyleProgress
+ status:status
+ superview:superview
+ completion:nil];
}
#pragma mark - Progress
+ (void)showProgress:(CGFloat)progress
{
- [self showProgress:progress
- status:nil];
+ [self showProgress:progress
+ status:nil];
}
+ (void)showProgress:(CGFloat)progress
- status:(NSString*)status
+ status:(NSString*)status
{
- [self showProgress:progress
- status:status
- onView:nil];
+ [self showProgress:progress
+ status:status
+ onView:nil];
}
+ (void)showProgress:(CGFloat)progress
- status:(NSString *)status
- onView:(UIView *)superview
+ status:(NSString *)status
+ onView:(UIView *)superview
{
- [self showHUDWithProgress:progress
- style:KVNProgressStyleProgress
- status:status
- superview:superview
- completion:nil];
+ [self showHUDWithProgress:progress
+ style:KVNProgressStyleProgress
+ status:status
+ superview:superview
+ completion:nil];
}
#pragma mark - Success
+ (void)showSuccess
{
- [self showSuccessWithStatus:nil];
+ [self showSuccessWithStatus:nil];
}
+ (void)showSuccessWithCompletion:(KVNCompletionBlock)completion
{
- [self showSuccessWithStatus:nil
- completion:completion];
+ [self showSuccessWithStatus:nil
+ completion:completion];
}
+ (void)showSuccessWithStatus:(NSString *)status
{
- [self showSuccessWithStatus:status
- onView:nil];
+ [self showSuccessWithStatus:status
+ onView:nil];
}
+ (void)showSuccessWithStatus:(NSString *)status
- completion:(KVNCompletionBlock)completion
+ completion:(KVNCompletionBlock)completion
{
- [self showSuccessWithStatus:status
- onView:nil
- completion:completion];
+ [self showSuccessWithStatus:status
+ onView:nil
+ completion:completion];
}
+ (void)showSuccessWithStatus:(NSString *)status
- onView:(UIView *)superview
+ onView:(UIView *)superview
{
- [self showSuccessWithStatus:status
- onView:superview
- completion:nil];
+ [self showSuccessWithStatus:status
+ onView:superview
+ completion:nil];
}
+ (void)showSuccessWithStatus:(NSString *)status
- onView:(UIView *)superview
- completion:(KVNCompletionBlock)completion
+ onView:(UIView *)superview
+ completion:(KVNCompletionBlock)completion
{
- [self showHUDWithProgress:KVNProgressIndeterminate
- style:KVNProgressStyleSuccess
- status:status
- superview:superview
- completion:completion];
+ [self showHUDWithProgress:KVNProgressIndeterminate
+ style:KVNProgressStyleSuccess
+ status:status
+ superview:superview
+ completion:completion];
}
#pragma mark - Error
+ (void)showError
{
- [self showErrorWithStatus:nil];
+ [self showErrorWithStatus:nil];
}
+ (void)showErrorWithCompletion:(KVNCompletionBlock)completion
{
- [self showErrorWithStatus:nil
- completion:completion];
+ [self showErrorWithStatus:nil
+ completion:completion];
}
+ (void)showErrorWithStatus:(NSString *)status
{
- [self showErrorWithStatus:status
- onView:nil];
+ [self showErrorWithStatus:status
+ onView:nil];
}
+ (void)showErrorWithStatus:(NSString *)status
- completion:(KVNCompletionBlock)completion
+ completion:(KVNCompletionBlock)completion
{
- [self showErrorWithStatus:status
- onView:nil
- completion:completion];
+ [self showErrorWithStatus:status
+ onView:nil
+ completion:completion];
}
+ (void)showErrorWithStatus:(NSString *)status
- onView:(UIView *)superview
+ onView:(UIView *)superview
{
- [self showErrorWithStatus:status
- onView:superview
- completion:nil];
+ [self showErrorWithStatus:status
+ onView:superview
+ completion:nil];
}
+ (void)showErrorWithStatus:(NSString *)status
- onView:(UIView *)superview
- completion:(KVNCompletionBlock)completion
+ onView:(UIView *)superview
+ completion:(KVNCompletionBlock)completion
{
- [self showHUDWithProgress:KVNProgressIndeterminate
- style:KVNProgressStyleError
- status:status
- superview:superview
- completion:completion];
+ [self showHUDWithProgress:KVNProgressIndeterminate
+ style:KVNProgressStyleError
+ status:status
+ superview:superview
+ completion:completion];
}
#pragma mark - Show
+ (void)showHUDWithProgress:(CGFloat)progress
- style:(KVNProgressStyle)style
- status:(NSString *)status
- superview:(UIView *)superview
- completion:(KVNCompletionBlock)completion
+ style:(KVNProgressStyle)style
+ status:(NSString *)status
+ superview:(UIView *)superview
+ completion:(KVNCompletionBlock)completion
{
- [[self sharedView] showProgress:progress
- status:status
- style:style
- backgroundType:configuration.backgroundType
- fullScreen:configuration.fullScreen
- view:superview
- completion:completion];
+ [[self sharedView] showProgress:progress
+ status:status
+ style:style
+ backgroundType:configuration.backgroundType
+ fullScreen:configuration.fullScreen
+ view:superview
+ completion:completion];
}
- (void)showProgress:(CGFloat)progress
- status:(NSString *)status
- style:(KVNProgressStyle)style
- backgroundType:(KVNProgressBackgroundType)backgroundType
- fullScreen:(BOOL)fullScreen
- view:(UIView *)superview
- completion:(KVNCompletionBlock)completion
-{
- KVNPrepareBlockSelf();
-
- // We check if a previous HUD is displaying
- // If so, we wait its minimum display time before switching to the new one
- // But, if we are changing from an indeterminate progress HUD to a determinate one,
- // we do not apply this rule
- if (![self isWaitingToChangeHUD] && self.style != KVNProgressStyleHidden
- && !(self.style == KVNProgressStyleProgress && self.progress == KVNProgressIndeterminate && progress != KVNProgressIndeterminate)
- && !(self.style == KVNProgressStyleProgress && self.progress != KVNProgressIndeterminate)) {
- self.waitingToChangeHUD = YES;
- self.state = KVNProgressStateShowed;
-
- NSTimeInterval timeIntervalSinceShow = [self.showActionTrigerredDate timeIntervalSinceNow];
- NSTimeInterval delay = 0;
-
- if (timeIntervalSinceShow < self.configuration.minimumDisplayTime) {
- // The hud hasn't showed enough time
- timeIntervalSinceShow = (timeIntervalSinceShow < 0) ? 0 : timeIntervalSinceShow;
- delay = self.configuration.minimumDisplayTime - timeIntervalSinceShow;
- }
-
- if (delay > 0) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- if (KVNBlockSelf.state == KVNProgressStateDismissing || ![KVNBlockSelf.class isVisible]) {
- // While waiting for displaying previous HUD enough time before showing the new one,
- // the dismiss method on this new HUD has already been called
- // So logically, we do not display the new HUD that is already dismissed (before even being displayed)
- return;
- }
-
- [KVNBlockSelf showProgress:progress
- status:status
- style:style
- backgroundType:backgroundType
- fullScreen:fullScreen
- view:superview
- completion:completion];
- });
-
- return;
- }
- }
-
- // We're going to create a new HUD
- self.waitingToChangeHUD = NO;
- self.progress = progress;
- self.status = [status copy];
- self.style = style;
- self.backgroundType = backgroundType;
- self.fullScreen = fullScreen;
-
- // If HUD is already added to the view we just update the UI
- if ([self.class isVisible]) {
- self.state = KVNProgressStateShowed;
-
- [UIView animateWithDuration:KVNLayoutAnimationDuration
- animations:^{
- [KVNBlockSelf setupUI];
- }];
-
- KVNBlockSelf.showActionTrigerredDate = [NSDate date];
- [KVNBlockSelf animateUI];
- } else {
- self.state = KVNProgressStateAppearing;
-
- if (superview) {
- [self addToView:superview];
- } else {
- [self addToCurrentWindow];
- }
-
- [self setupUI];
-
- // FIXME: find a way to wait for the views to be added to the window before launching the animations
- // (Fix to make the animations work fine)
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [KVNBlockSelf animateUI];
- [KVNBlockSelf animateAppearance];
- });
- }
-
- // If it's an auto-dismissable HUD
- if (self.style != KVNProgressStyleProgress) {
- NSTimeInterval delay;
- switch (self.style) {
- case KVNProgressStyleProgress:
- // should never happen
- return;
- case KVNProgressStyleSuccess:
- delay = self.configuration.minimumSuccessDisplayTime;
- break;
- case KVNProgressStyleError:
- delay = self.configuration.minimumErrorDisplayTime;
- break;
- case KVNProgressStyleHidden:
- // should never happen
- return;
- }
-
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [KVNBlockSelf.class dismissWithCompletion:completion];
- });
- }
-}
-
-#pragma mark - Dimiss
+ status:(NSString *)status
+ style:(KVNProgressStyle)style
+ backgroundType:(KVNProgressBackgroundType)backgroundType
+ fullScreen:(BOOL)fullScreen
+ view:(UIView *)superview
+ completion:(KVNCompletionBlock)completion
+{
+ KVNPrepareBlockSelf();
+
+ dispatch_async(self.queue, ^{
+
+ BOOL styleDidChange = self.style != style;
+
+ // We're going to create a new HUD
+ self.progress = progress;
+ self.status = [status copy];
+ self.style = style;
+ self.backgroundType = backgroundType;
+ self.fullScreen = fullScreen;
+
+ switch (self.state) {
+ case KVNProgressStateHidden: {
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ KVNBlockSelf.state = KVNProgressStateAppearing;
+
+ if (superview) {
+ [KVNBlockSelf addToView:superview];
+ } else {
+ [KVNBlockSelf addToCurrentWindow];
+ }
+
+ [KVNBlockSelf setupUI];
+ [KVNBlockSelf animateUI];
+ [KVNBlockSelf animateAppearance];
+ });
+
+ // We need a strong reference to get the semaphore
+ KVNProgress *strongSelf = KVNBlockSelf;
+
+ // Wait until the ui animation end before we have appeared
+ dispatch_semaphore_wait(strongSelf.semaphore, DISPATCH_TIME_FOREVER);
+
+ strongSelf.state = KVNProgressStateShowed;
+ }
+ break;
+
+ case KVNProgressStateAppearing:
+ case KVNProgressStateDismissing: {
+ // Should never see these states.
+ }
+ break;
+
+ case KVNProgressStateShowed: {
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ [UIView animateWithDuration:KVNLayoutAnimationDuration
+ animations:^{
+ [KVNBlockSelf setupUI];
+ }];
+
+ KVNBlockSelf.showActionTrigerredDate = [NSDate date];
+ [KVNBlockSelf animateUI];
+ });
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (styleDidChange) {
+ NSTimeInterval delay;
+ switch (self.style) {
+ case KVNProgressStyleProgress:
+ delay = self.configuration.minimumDisplayTime;
+ break;
+ case KVNProgressStyleSuccess:
+ delay = self.configuration.minimumSuccessDisplayTime;
+ break;
+ case KVNProgressStyleError:
+ delay = self.configuration.minimumErrorDisplayTime;
+ break;
+ case KVNProgressStyleHidden:
+ // Should not happen
+ delay = 0;
+ break;
+ }
+
+ // Ok, now wait for our minimum time
+ [NSThread sleepForTimeInterval:delay];
+
+ // If it's an auto-dismissable HUD
+ switch (self.style) {
+ case KVNProgressStyleProgress:
+ // Do nothing.
+ break;
+
+ case KVNProgressStyleSuccess:
+ case KVNProgressStyleError: {
+ [KVNBlockSelf.class synchronousDismissWithCompletion:completion];
+ }
+ break;
+
+ case KVNProgressStyleHidden:
+ // should never happen
+ break;
+ }
+ }
+ });
+}
+
+#pragma mark - Dismiss
+ (void)dismiss
{
- [self dismissWithCompletion:nil];
+ [self dismissWithCompletion:nil];
+}
+
+/**
+ Since this method synchronously dispatches to the main thread it
+ can *not* be called from it. If it does, deadlock.
+ */
++ (void)synchronousDismissWithCompletion:(KVNCompletionBlock)completion
+{
+ switch ([self sharedView].state) {
+ case KVNProgressStateShowed: {
+ [self sharedView].state = KVNProgressStateDismissing;
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ [self dismissAnimatedWithCompletion:completion];
+ });
+
+ dispatch_semaphore_wait([self sharedView].semaphore, DISPATCH_TIME_FOREVER);
+
+ [self sharedView].state = KVNProgressStateHidden;
+ }
+ break;
+
+ case KVNProgressStateAppearing:
+ case KVNProgressStateDismissing: {
+ // Should not see these states.
+ }
+ break;
+
+ case KVNProgressStateHidden: {
+ // Do nothing
+ }
+ break;
+
+ default:
+ break;
+ }
}
+ (void)dismissWithCompletion:(KVNCompletionBlock)completion
{
- if ([self sharedView].state == KVNProgressStateHidden) {
- return;
- } else if ([self sharedView].state == KVNProgressStateAppearing) {
- [self sharedView].state = KVNProgressStateDismissing;
- [self endDismissWithCompletion:completion];
- }
-
- [self sharedView].state = KVNProgressStateDismissing;
-
- // FIXME: find a way to wait for the views to be added to the window before launching the animations
- // (Fix to make the dismiss work fine)
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- // If the view has changed or will change, the state property is set back to showed so we don't dismiss
- // the (scheduled) new one
- if ([self sharedView].state == KVNProgressStateDismissing) {
- [self dismissAnimatedWithCompletion:completion];
- }
- });
+ dispatch_async([self sharedView].queue, ^{
+
+ [self synchronousDismissWithCompletion:completion];
+ });
}
+ (void)dismissAnimatedWithCompletion:(KVNCompletionBlock)completion
{
- KVNProgress *progressView = [self sharedView];
-
- NSTimeInterval timeIntervalSinceShow = fabs([progressView.showActionTrigerredDate timeIntervalSinceNow]);
- NSTimeInterval delay = 0;
-
- if (timeIntervalSinceShow < progressView.configuration.minimumDisplayTime) {
- // The hud hasn't showed enough time
- delay = progressView.configuration.minimumDisplayTime - timeIntervalSinceShow;
- }
-
- [UIView animateWithDuration:KVNFadeAnimationDuration
- delay:delay
- options:(UIViewAnimationOptionCurveEaseIn
- | UIViewAnimationOptionAllowUserInteraction
- | UIViewAnimationOptionBeginFromCurrentState)
- animations:^{
- if ([self sharedView].state == KVNProgressStateDismissing) {
- progressView.alpha = 0.0f;
- }
- } completion:^(BOOL finished) {
- if(progressView.alpha == 0 || progressView.contentView.alpha == 0) {
- [self endDismissWithCompletion:completion];
- }
- }];
+ KVNProgress *progressView = [self sharedView];
+
+ NSTimeInterval timeIntervalSinceShow = fabs([progressView.showActionTrigerredDate timeIntervalSinceNow]);
+ NSTimeInterval delay = 0;
+
+ if (timeIntervalSinceShow < progressView.configuration.minimumDisplayTime) {
+ // The hud hasn't showed enough time
+ delay = progressView.configuration.minimumDisplayTime - timeIntervalSinceShow;
+ }
+
+ [UIView animateWithDuration:KVNFadeAnimationDuration
+ delay:delay
+ options:(UIViewAnimationOptionCurveEaseIn
+ | UIViewAnimationOptionAllowUserInteraction
+ | UIViewAnimationOptionBeginFromCurrentState)
+ animations:^{
+ if ([self sharedView].state == KVNProgressStateDismissing) {
+ progressView.alpha = 0.0f;
+ }
+ } completion:^(BOOL finished) {
+ if(progressView.alpha == 0 || progressView.contentView.alpha == 0) {
+ [self endDismissWithCompletion:completion];
+ }
+ }];
}
+ (void)endDismissWithCompletion:(KVNCompletionBlock)completion
{
- KVNProgress *progressView = [self sharedView];
-
- if (progressView.state == KVNProgressStateDismissing) {
- [self sharedView].state = KVNProgressStateHidden;
-
- [progressView cancelCircleAnimation];
- [progressView removeFromSuperview];
-
- progressView.style = KVNProgressStyleHidden;
-
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
-
- // Tell the rootViewController to update the StatusBar appearance
- UIViewController *rootController = [[UIApplication sharedApplication] keyWindow].rootViewController;
- if ([rootController respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
- [rootController setNeedsStatusBarAppearanceUpdate];
- }
- }
-
- if (completion) {
- dispatch_async(dispatch_get_main_queue(), ^{
- completion();
- });
- }
+ KVNProgress *progressView = [self sharedView];
+
+ if (progressView.state == KVNProgressStateDismissing) {
+ [self sharedView].state = KVNProgressStateHidden;
+
+ [progressView cancelCircleAnimation];
+ [progressView removeFromSuperview];
+
+ progressView.style = KVNProgressStyleHidden;
+
+ UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
+
+ // Tell the rootViewController to update the StatusBar appearance
+ UIViewController *rootController = [[UIApplication sharedApplication] keyWindow].rootViewController;
+ if ([rootController respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
+ [rootController setNeedsStatusBarAppearanceUpdate];
+ }
+ }
+
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion();
+ });
+ }
+
+ // Notify the dismiss block that the dismiss action is finished.
+ dispatch_semaphore_signal(progressView.semaphore);
}
#pragma mark - UI
- (void)setupUI
{
- [self setupGestures];
- [self setupConstraints];
- [self setupCircleProgressView];
- [self setupStatus:self.status];
- [self setupBackground];
+ [self setupGestures];
+ [self setupConstraints];
+ [self setupCircleProgressView];
+ [self setupStatus:self.status];
+ [self setupBackground];
}
- (void)setupGestures
{
- for (UIGestureRecognizer *gestureRecognizer in self.gestureRecognizers) {
- [self removeGestureRecognizer:gestureRecognizer];
- }
-
- if (self.configuration.tapBlock) {
- UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(performTapBlock)];
- [self addGestureRecognizer:tapGestureRecognizer];
- }
+ for (UIGestureRecognizer *gestureRecognizer in self.gestureRecognizers) {
+ [self removeGestureRecognizer:gestureRecognizer];
+ }
+
+ if (self.configuration.tapBlock) {
+ UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(performTapBlock)];
+ [self addGestureRecognizer:tapGestureRecognizer];
+ }
}
- (void)setupConstraints
{
- CGRect bounds = [self correctedBounds];
- CGFloat statusInset = (self.status.length > 0) ? KVNContentViewWithStatusInset : KVNContentViewWithoutStatusInset;
- CGFloat contentWidth;
-
- if (!KVNSystemVersionGreaterOrEqual_iOS_8 && [self.superview isKindOfClass:UIWindow.class]) {
- self.transform = CGAffineTransformMakeRotation([self rotationForStatusBarOrientation]);
- } else {
- self.transform = CGAffineTransformIdentity;
- }
-
- if ([self isFullScreen]) {
- contentWidth = CGRectGetWidth(bounds) - (2 * KVNContentViewFullScreenModeLeadingAndTrailingSpaceConstraintConstant);
- } else {
- if (KVNIpad) {
- contentWidth = KVNAlertViewWidth;
- } else {
- contentWidth = CGRectGetWidth(bounds) - (2 * KVNContentViewNotFullScreenModeLeadingAndTrailingSpaceConstraintConstant);
-
- if (contentWidth > KVNAlertViewWidth) {
- contentWidth = KVNAlertViewWidth;
- }
- }
- }
-
- self.circleProgressViewTopToSuperViewConstraint.constant = statusInset;
- self.statusLabelBottomToSuperViewConstraint.constant = statusInset;
- self.contentViewWidthConstraint.constant = contentWidth;
-
- [self layoutIfNeeded];
+ CGRect bounds = [self correctedBounds];
+ CGFloat statusInset = (self.status.length > 0) ? KVNContentViewWithStatusInset : KVNContentViewWithoutStatusInset;
+ CGFloat contentWidth;
+
+ if (!KVNSystemVersionGreaterOrEqual_iOS_8 && [self.superview isKindOfClass:UIWindow.class]) {
+ self.transform = CGAffineTransformMakeRotation([self rotationForStatusBarOrientation]);
+ } else {
+ self.transform = CGAffineTransformIdentity;
+ }
+
+ if ([self isFullScreen]) {
+ contentWidth = CGRectGetWidth(bounds) - (2 * KVNContentViewFullScreenModeLeadingAndTrailingSpaceConstraintConstant);
+ } else {
+ if (KVNIpad) {
+ contentWidth = KVNAlertViewWidth;
+ } else {
+ contentWidth = CGRectGetWidth(bounds) - (2 * KVNContentViewNotFullScreenModeLeadingAndTrailingSpaceConstraintConstant);
+
+ if (contentWidth > KVNAlertViewWidth) {
+ contentWidth = KVNAlertViewWidth;
+ }
+ }
+ }
+
+ self.circleProgressViewTopToSuperViewConstraint.constant = statusInset;
+ self.statusLabelBottomToSuperViewConstraint.constant = statusInset;
+ self.contentViewWidthConstraint.constant = contentWidth;
+
+ [self layoutIfNeeded];
}
- (void)setupCircleProgressView
{
- // Constraints
- self.circleProgressViewWidthConstraint.constant = self.configuration.circleSize;
- self.circleProgressViewHeightConstraint.constant = self.configuration.circleSize;
-
- [self layoutIfNeeded];
-
- // Circle shape
- self.circleProgressView.layer.cornerRadius = (self.configuration.circleSize / 2.0f);
- self.circleProgressView.layer.masksToBounds = YES;
- self.circleProgressView.backgroundColor = [UIColor clearColor];
-
- // Remove all previous added layers
- [self removeAllSubLayersOfLayer:self.circleProgressView.layer];
+ // Constraints
+ self.circleProgressViewWidthConstraint.constant = self.configuration.circleSize;
+ self.circleProgressViewHeightConstraint.constant = self.configuration.circleSize;
+
+ [self layoutIfNeeded];
+
+ // Circle shape
+ self.circleProgressView.layer.cornerRadius = (self.configuration.circleSize / 2.0f);
+ self.circleProgressView.layer.masksToBounds = YES;
+ self.circleProgressView.backgroundColor = [UIColor clearColor];
+
+ // Remove all previous added layers
+ [self removeAllSubLayersOfLayer:self.circleProgressView.layer];
}
- (void)setupInfiniteCircle
{
- CGFloat radius = (self.configuration.circleSize / 2.0f);
- CGPoint center = CGPointMake(radius, radius);
-
- UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center
- radius:(radius - self.configuration.lineWidth)
- startAngle:GLKMathDegreesToRadians(-45.0f)
- endAngle:GLKMathDegreesToRadians(275.0f)
- clockwise:YES];
-
- self.circleProgressLineLayer = [CAShapeLayer layer];
- self.circleProgressLineLayer.path = circlePath.CGPath;
- self.circleProgressLineLayer.strokeColor = self.configuration.circleStrokeForegroundColor.CGColor;
- self.circleProgressLineLayer.fillColor = self.configuration.circleFillBackgroundColor.CGColor;
- self.circleProgressLineLayer.lineWidth = self.configuration.lineWidth;
-
- [self.circleProgressView.layer addSublayer:self.circleProgressLineLayer];
-
- [self.circleProgressLineLayer removeAllAnimations];
- [self.circleProgressView.layer removeAllAnimations];
- [self animateCircleWithInfiniteLoop];
+ CGFloat radius = (self.configuration.circleSize / 2.0f);
+ CGPoint center = CGPointMake(radius, radius);
+
+ UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center
+ radius:(radius - self.configuration.lineWidth)
+ startAngle:GLKMathDegreesToRadians(-45.0f)
+ endAngle:GLKMathDegreesToRadians(275.0f)
+ clockwise:YES];
+
+ self.circleProgressLineLayer = [CAShapeLayer layer];
+ self.circleProgressLineLayer.path = circlePath.CGPath;
+ self.circleProgressLineLayer.strokeColor = self.configuration.circleStrokeForegroundColor.CGColor;
+ self.circleProgressLineLayer.fillColor = self.configuration.circleFillBackgroundColor.CGColor;
+ self.circleProgressLineLayer.lineWidth = self.configuration.lineWidth;
+
+ [self.circleProgressView.layer addSublayer:self.circleProgressLineLayer];
+
+ [self.circleProgressLineLayer removeAllAnimations];
+ [self.circleProgressView.layer removeAllAnimations];
+ [self animateCircleWithInfiniteLoop];
}
- (void)setupProgressCircle
{
- CGFloat radius = (self.configuration.circleSize / 2.0f);
- CGPoint center = CGPointMake(radius, radius);
-
- UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center
- radius:(radius - self.configuration.lineWidth)
- startAngle:GLKMathDegreesToRadians(-90.0f)
- endAngle:GLKMathDegreesToRadians(275.0f)
- clockwise:YES];
-
- [self cancelCircleAnimation];
-
- self.circleProgressLineLayer = [CAShapeLayer layer];
- self.circleProgressLineLayer.path = circlePath.CGPath;
- self.circleProgressLineLayer.strokeColor = self.configuration.circleStrokeForegroundColor.CGColor;
- self.circleProgressLineLayer.fillColor = [UIColor clearColor].CGColor;
- self.circleProgressLineLayer.lineWidth = self.configuration.lineWidth;
-
- self.circleBackgroundLineLayer = [CAShapeLayer layer];
- self.circleBackgroundLineLayer.path = circlePath.CGPath;
- self.circleBackgroundLineLayer.strokeColor = self.configuration.circleStrokeBackgroundColor.CGColor;
- self.circleBackgroundLineLayer.fillColor = self.configuration.circleFillBackgroundColor.CGColor;
- self.circleBackgroundLineLayer.lineWidth = self.configuration.lineWidth;
-
- [self.circleProgressView.layer addSublayer:self.circleBackgroundLineLayer];
- [self.circleProgressView.layer addSublayer:self.circleProgressLineLayer];
-
- [self.circleProgressLineLayer removeAllAnimations];
- [self.circleProgressView.layer removeAllAnimations];
-
- [self updateProgress:self.progress
- animated:NO];
+ CGFloat radius = (self.configuration.circleSize / 2.0f);
+ CGPoint center = CGPointMake(radius, radius);
+
+ UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center
+ radius:(radius - self.configuration.lineWidth)
+ startAngle:GLKMathDegreesToRadians(-90.0f)
+ endAngle:GLKMathDegreesToRadians(275.0f)
+ clockwise:YES];
+
+ [self cancelCircleAnimation];
+
+ self.circleProgressLineLayer = [CAShapeLayer layer];
+ self.circleProgressLineLayer.path = circlePath.CGPath;
+ self.circleProgressLineLayer.strokeColor = self.configuration.circleStrokeForegroundColor.CGColor;
+ self.circleProgressLineLayer.fillColor = [UIColor clearColor].CGColor;
+ self.circleProgressLineLayer.lineWidth = self.configuration.lineWidth;
+
+ self.circleBackgroundLineLayer = [CAShapeLayer layer];
+ self.circleBackgroundLineLayer.path = circlePath.CGPath;
+ self.circleBackgroundLineLayer.strokeColor = self.configuration.circleStrokeBackgroundColor.CGColor;
+ self.circleBackgroundLineLayer.fillColor = self.configuration.circleFillBackgroundColor.CGColor;
+ self.circleBackgroundLineLayer.lineWidth = self.configuration.lineWidth;
+
+ [self.circleProgressView.layer addSublayer:self.circleBackgroundLineLayer];
+ [self.circleProgressView.layer addSublayer:self.circleProgressLineLayer];
+
+ [self.circleProgressLineLayer removeAllAnimations];
+ [self.circleProgressView.layer removeAllAnimations];
+
+ [self updateProgress:self.progress
+ animated:NO];
}
- (void)setupSuccessUI
{
- [self setupFullRoundCircleWithColor:self.configuration.successColor];
-
- UIBezierPath* checkmarkPath = [UIBezierPath bezierPath];
- [checkmarkPath moveToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.28f, CGRectGetHeight(self.circleProgressView.bounds) * 0.53f)];
- [checkmarkPath addLineToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.42f, CGRectGetHeight(self.circleProgressView.bounds) * 0.66f)];
- [checkmarkPath addLineToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.72f, CGRectGetHeight(self.circleProgressView.bounds) * 0.36f)];
- checkmarkPath.lineCapStyle = kCGLineCapSquare;
-
- self.checkmarkLayer = [CAShapeLayer layer];
- self.checkmarkLayer.path = checkmarkPath.CGPath;
- self.checkmarkLayer.fillColor = nil;
- self.checkmarkLayer.strokeColor = self.configuration.successColor.CGColor;
- self.checkmarkLayer.lineWidth = self.configuration.lineWidth;
-
- [self.circleProgressView.layer addSublayer:self.circleProgressLineLayer];
- [self.circleProgressView.layer addSublayer:self.checkmarkLayer];
-
- [self.circleProgressLineLayer removeAllAnimations];
- [self.circleProgressView.layer removeAllAnimations];
- [self.checkmarkLayer removeAllAnimations];
- [self animateSuccess];
+ [self setupFullRoundCircleWithColor:self.configuration.successColor];
+
+ UIBezierPath* checkmarkPath = [UIBezierPath bezierPath];
+ [checkmarkPath moveToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.28f, CGRectGetHeight(self.circleProgressView.bounds) * 0.53f)];
+ [checkmarkPath addLineToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.42f, CGRectGetHeight(self.circleProgressView.bounds) * 0.66f)];
+ [checkmarkPath addLineToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.72f, CGRectGetHeight(self.circleProgressView.bounds) * 0.36f)];
+ checkmarkPath.lineCapStyle = kCGLineCapSquare;
+
+ self.checkmarkLayer = [CAShapeLayer layer];
+ self.checkmarkLayer.path = checkmarkPath.CGPath;
+ self.checkmarkLayer.fillColor = nil;
+ self.checkmarkLayer.strokeColor = self.configuration.successColor.CGColor;
+ self.checkmarkLayer.lineWidth = self.configuration.lineWidth;
+
+ [self.circleProgressView.layer addSublayer:self.circleProgressLineLayer];
+ [self.circleProgressView.layer addSublayer:self.checkmarkLayer];
+
+ [self.circleProgressLineLayer removeAllAnimations];
+ [self.circleProgressView.layer removeAllAnimations];
+ [self.checkmarkLayer removeAllAnimations];
+ [self animateSuccess];
}
- (void)setupErrorUI
{
- [self setupFullRoundCircleWithColor:self.configuration.errorColor];
-
- UIBezierPath* crossPath = [UIBezierPath bezierPath];
- [crossPath moveToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.72f, CGRectGetHeight(self.circleProgressView.bounds) * 0.27f)];
- [crossPath addLineToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.27f, CGRectGetHeight(self.circleProgressView.bounds) * 0.72f)];
- [crossPath moveToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.27f, CGRectGetHeight(self.circleProgressView.bounds) * 0.27f)];
- [crossPath addLineToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.72f, CGRectGetHeight(self.circleProgressView.bounds) * 0.72f)];
- crossPath.lineCapStyle = kCGLineCapSquare;
-
- self.crossLayer = [CAShapeLayer layer];
- self.crossLayer.path = crossPath.CGPath;
- self.crossLayer.fillColor = nil;
- self.crossLayer.strokeColor = self.configuration.errorColor.CGColor;
- self.crossLayer.lineWidth = self.configuration.lineWidth;
-
- [self.circleProgressView.layer addSublayer:self.circleProgressLineLayer];
- [self.circleProgressView.layer addSublayer:self.crossLayer];
-
- [self.circleProgressLineLayer removeAllAnimations];
- [self.circleProgressView.layer removeAllAnimations];
- [self.crossLayer removeAllAnimations];
- [self animateError];
+ [self setupFullRoundCircleWithColor:self.configuration.errorColor];
+
+ UIBezierPath* crossPath = [UIBezierPath bezierPath];
+ [crossPath moveToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.72f, CGRectGetHeight(self.circleProgressView.bounds) * 0.27f)];
+ [crossPath addLineToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.27f, CGRectGetHeight(self.circleProgressView.bounds) * 0.72f)];
+ [crossPath moveToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.27f, CGRectGetHeight(self.circleProgressView.bounds) * 0.27f)];
+ [crossPath addLineToPoint:CGPointMake(CGRectGetWidth(self.circleProgressView.bounds) * 0.72f, CGRectGetHeight(self.circleProgressView.bounds) * 0.72f)];
+ crossPath.lineCapStyle = kCGLineCapSquare;
+
+ self.crossLayer = [CAShapeLayer layer];
+ self.crossLayer.path = crossPath.CGPath;
+ self.crossLayer.fillColor = nil;
+ self.crossLayer.strokeColor = self.configuration.errorColor.CGColor;
+ self.crossLayer.lineWidth = self.configuration.lineWidth;
+
+ [self.circleProgressView.layer addSublayer:self.circleProgressLineLayer];
+ [self.circleProgressView.layer addSublayer:self.crossLayer];
+
+ [self.circleProgressLineLayer removeAllAnimations];
+ [self.circleProgressView.layer removeAllAnimations];
+ [self.crossLayer removeAllAnimations];
+ [self animateError];
}
- (void)setupFullRoundCircleWithColor:(UIColor *)color
{
- CGFloat radius = (self.configuration.circleSize / 2.0f);
- CGPoint center = CGPointMake(radius, radius);
-
- // Circle
- UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center
- radius:(radius - self.configuration.lineWidth)
- startAngle:GLKMathDegreesToRadians(-90.0f)
- endAngle:GLKMathDegreesToRadians(275.0f)
- clockwise:YES];
-
- self.circleProgressLineLayer = [CAShapeLayer layer];
- self.circleProgressLineLayer.path = circlePath.CGPath;
- self.circleProgressLineLayer.strokeColor = color.CGColor;
- self.circleProgressLineLayer.fillColor = self.configuration.circleFillBackgroundColor.CGColor;
- self.circleProgressLineLayer.lineWidth = self.configuration.lineWidth;
+ CGFloat radius = (self.configuration.circleSize / 2.0f);
+ CGPoint center = CGPointMake(radius, radius);
+
+ // Circle
+ UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:center
+ radius:(radius - self.configuration.lineWidth)
+ startAngle:GLKMathDegreesToRadians(-90.0f)
+ endAngle:GLKMathDegreesToRadians(275.0f)
+ clockwise:YES];
+
+ self.circleProgressLineLayer = [CAShapeLayer layer];
+ self.circleProgressLineLayer.path = circlePath.CGPath;
+ self.circleProgressLineLayer.strokeColor = color.CGColor;
+ self.circleProgressLineLayer.fillColor = self.configuration.circleFillBackgroundColor.CGColor;
+ self.circleProgressLineLayer.lineWidth = self.configuration.lineWidth;
}
- (void)setupStatus:(NSString *)status
{
- self.status = status;
-
- BOOL showStatus = (self.status.length > 0);
-
- CATransition *animation = [CATransition animation];
- animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
- animation.type = kCATransitionFade;
- animation.duration = KVNTextUpdateAnimationDuration;
- [self.statusLabel.layer addAnimation:animation forKey:@"kCATransitionFade"];
-
- self.statusLabel.text = self.status;
- self.statusLabel.textColor = self.configuration.statusColor;
- self.statusLabel.font = self.configuration.statusFont;
- self.statusLabel.hidden = !showStatus;
-
- [self updateStatusConstraints];
+ self.status = status;
+
+ BOOL showStatus = (self.status.length > 0);
+
+ CATransition *animation = [CATransition animation];
+ animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ animation.type = kCATransitionFade;
+ animation.duration = KVNTextUpdateAnimationDuration;
+ [self.statusLabel.layer addAnimation:animation forKey:@"kCATransitionFade"];
+
+ self.statusLabel.text = self.status;
+ self.statusLabel.textColor = self.configuration.statusColor;
+ self.statusLabel.font = self.configuration.statusFont;
+ self.statusLabel.hidden = !showStatus;
+
+ [self updateStatusConstraints];
}
- (void)setupBackground
{
- if ([self.class isVisible]) {
- return; // No reload of background when view is showing
- }
-
- [self updateBackground];
-
- KVNPrepareBlockSelf();
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- [KVNBlockSelf setupMotionEffect];
- });
+ if ([self.class isVisible]) {
+ return; // No reload of background when view is showing
+ }
+
+ [self updateBackground];
+
+ KVNPrepareBlockSelf();
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ [KVNBlockSelf setupMotionEffect];
+ });
}
- (void)setupMotionEffect
{
- UIInterpolatingMotionEffect *xAxis = [self motionEffectWithType:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis
- keyPath:@"center.x"];
- UIInterpolatingMotionEffect *yAxis = [self motionEffectWithType:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis
- keyPath:@"center.y"];
- UIMotionEffectGroup *group = [[UIMotionEffectGroup alloc] init];
- group.motionEffects = @[xAxis, yAxis];
-
- [self.contentView addMotionEffect:group];
+ UIInterpolatingMotionEffect *xAxis = [self motionEffectWithType:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis
+ keyPath:@"center.x"];
+ UIInterpolatingMotionEffect *yAxis = [self motionEffectWithType:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis
+ keyPath:@"center.y"];
+ UIMotionEffectGroup *group = [[UIMotionEffectGroup alloc] init];
+ group.motionEffects = @[xAxis, yAxis];
+
+ [self.contentView addMotionEffect:group];
}
- (void)addToCurrentWindow
{
- UIWindow *currentWindow = nil;
-
- NSEnumerator *frontToBackWindows = [[[UIApplication sharedApplication] windows] reverseObjectEnumerator];
-
- for (UIWindow *window in frontToBackWindows) {
- if (window.windowLevel == UIWindowLevelNormal) {
- currentWindow = window;
- break;
- }
- }
-
- if (self.superview != currentWindow) {
- [self addToView:currentWindow];
- }
+ UIWindow *currentWindow = nil;
+
+ NSEnumerator *frontToBackWindows = [[[UIApplication sharedApplication] windows] reverseObjectEnumerator];
+
+ for (UIWindow *window in frontToBackWindows) {
+ if (window.windowLevel == UIWindowLevelNormal) {
+ currentWindow = window;
+ break;
+ }
+ }
+
+ if (self.superview != currentWindow) {
+ [self addToView:currentWindow];
+ }
}
- (void)addToView:(UIView *)superview
{
- if (self.superview) {
- [self.superview removeConstraints:self.constraintsToSuperview];
- [self removeFromSuperview];
- }
-
- [superview addSubview:self];
- [superview bringSubviewToFront:self];
-
- NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[self]|"
- options:0
- metrics:nil
- views:@{@"self" : self}];
- NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[self]|"
- options:0
- metrics:nil
- views:@{@"self" : self}];
-
- self.constraintsToSuperview = [verticalConstraints arrayByAddingObjectsFromArray:horizontalConstraints];
-
- self.translatesAutoresizingMaskIntoConstraints = NO;
- [superview addConstraints:verticalConstraints];
- [superview addConstraints:horizontalConstraints];
-
- [self layoutIfNeeded];
-
- self.alpha = 0.0f;
+ if (self.superview) {
+ [self.superview removeConstraints:self.constraintsToSuperview];
+ [self removeFromSuperview];
+ }
+
+ [superview addSubview:self];
+ [superview bringSubviewToFront:self];
+
+ NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[self]|"
+ options:0
+ metrics:nil
+ views:@{@"self" : self}];
+ NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[self]|"
+ options:0
+ metrics:nil
+ views:@{@"self" : self}];
+
+ self.constraintsToSuperview = [verticalConstraints arrayByAddingObjectsFromArray:horizontalConstraints];
+
+ self.translatesAutoresizingMaskIntoConstraints = NO;
+ [superview addConstraints:verticalConstraints];
+ [superview addConstraints:horizontalConstraints];
+
+ [self layoutIfNeeded];
+
+ self.alpha = 0.0f;
}
#pragma mark - Update
- (void)updateUIForOrientation
{
- [self setupConstraints];
- [self updateStatusConstraints];
- [self updateBackgroundConstraints];
+ [self setupConstraints];
+ [self updateStatusConstraints];
+ [self updateBackgroundConstraints];
}
- (void)updateBackground
{
- UIImage *backgroundImage = nil;
- UIColor *backgroundColor = nil;
-
- switch (self.backgroundType) {
- case KVNProgressBackgroundTypeSolid:
- backgroundImage = [UIImage emptyImage];
- backgroundColor = self.configuration.backgroundFillColor;
- break;
- case KVNProgressBackgroundTypeBlurred:
- backgroundImage = [self blurredScreenShot];
- backgroundColor = [UIColor clearColor];
- break;
- }
-
- if (!KVNSystemVersionGreaterOrEqual_iOS_8
- && !CGAffineTransformEqualToTransform(self.transform, CGAffineTransformIdentity))
- {
- CIImage *transformedCIImage = backgroundImage.CIImage;
-
- if (!transformedCIImage) {
- transformedCIImage = [CIImage imageWithCGImage:backgroundImage.CGImage];
- }
-
- transformedCIImage = [transformedCIImage imageByApplyingTransform:self.transform];
- backgroundImage = [UIImage imageWithCIImage:transformedCIImage];
- }
-
- [self updateBackgroundConstraints];
-
- if ([self isFullScreen])
- {
- self.backgroundImageView.image = backgroundImage;
- self.backgroundImageView.backgroundColor = backgroundColor;
-
- self.contentView.layer.cornerRadius = 0.0f;
- self.contentView.layer.masksToBounds = NO;
- self.contentView.image = [UIImage emptyImage];
- self.contentView.backgroundColor = [UIColor clearColor];
- }
- else
- {
- self.backgroundImageView.image = [UIImage emptyImage];
- self.backgroundImageView.backgroundColor = [UIColor colorWithWhite:0.0f
- alpha:0.35f];
-
- self.contentView.layer.cornerRadius = (self.status) ? KVNContentViewCornerRadius : KVNContentViewWithoutStatusCornerRadius;
- self.contentView.layer.masksToBounds = YES;
- self.contentView.contentMode = UIViewContentModeCenter;
- self.contentView.backgroundColor = self.configuration.backgroundFillColor;
-
- self.contentView.image = backgroundImage;
- }
+ UIImage *backgroundImage = nil;
+ UIColor *backgroundColor = nil;
+
+ switch (self.backgroundType) {
+ case KVNProgressBackgroundTypeSolid:
+ backgroundImage = [UIImage emptyImage];
+ backgroundColor = self.configuration.backgroundFillColor;
+ break;
+ case KVNProgressBackgroundTypeBlurred:
+ backgroundImage = [self blurredScreenShot];
+ backgroundColor = [UIColor clearColor];
+ break;
+ }
+
+ if (!KVNSystemVersionGreaterOrEqual_iOS_8
+ && !CGAffineTransformEqualToTransform(self.transform, CGAffineTransformIdentity))
+ {
+ CIImage *transformedCIImage = backgroundImage.CIImage;
+
+ if (!transformedCIImage) {
+ transformedCIImage = [CIImage imageWithCGImage:backgroundImage.CGImage];
+ }
+
+ transformedCIImage = [transformedCIImage imageByApplyingTransform:self.transform];
+ backgroundImage = [UIImage imageWithCIImage:transformedCIImage];
+ }
+
+ [self updateBackgroundConstraints];
+
+ if ([self isFullScreen])
+ {
+ self.backgroundImageView.image = backgroundImage;
+ self.backgroundImageView.backgroundColor = backgroundColor;
+
+ self.contentView.layer.cornerRadius = 0.0f;
+ self.contentView.layer.masksToBounds = NO;
+ self.contentView.image = [UIImage emptyImage];
+ self.contentView.backgroundColor = [UIColor clearColor];
+ }
+ else
+ {
+ self.backgroundImageView.image = [UIImage emptyImage];
+ self.backgroundImageView.backgroundColor = [UIColor colorWithWhite:0.0f
+ alpha:0.35f];
+
+ self.contentView.layer.cornerRadius = (self.status) ? KVNContentViewCornerRadius : KVNContentViewWithoutStatusCornerRadius;
+ self.contentView.layer.masksToBounds = YES;
+ self.contentView.contentMode = UIViewContentModeCenter;
+ self.contentView.backgroundColor = self.configuration.backgroundFillColor;
+
+ self.contentView.image = backgroundImage;
+ }
}
- (void)updateBackgroundConstraints
{
- if (![self isFullScreen] && self.status.length == 0) {
- self.circleProgressViewTopToSuperViewConstraint.constant = KVNContentViewWithoutStatusInset;
- self.statusLabelBottomToSuperViewConstraint.constant = KVNContentViewWithoutStatusInset;
-
- // We sets the width as the height to have a square
- CGSize fittingSize = [self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
- self.contentViewWidthConstraint.constant = fittingSize.height;
- }
+ if (![self isFullScreen] && self.status.length == 0) {
+ self.circleProgressViewTopToSuperViewConstraint.constant = KVNContentViewWithoutStatusInset;
+ self.statusLabelBottomToSuperViewConstraint.constant = KVNContentViewWithoutStatusInset;
+
+ // We sets the width as the height to have a square
+ CGSize fittingSize = [self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
+ self.contentViewWidthConstraint.constant = fittingSize.height;
+ }
}
+ (void)updateStatus:(NSString*)status
{
- [[self sharedView] updateStatus:status];
+ dispatch_async([self sharedView].queue, ^{
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ [[self sharedView] updateStatus:status];
+ });
+ });
}
- (void)updateStatus:(NSString *)status
{
- if ([self.class isVisible]) {
- [UIView animateWithDuration:KVNLayoutAnimationDuration
- animations:^{
- [self setupStatus:status];
- }];
- } else {
- [self setupStatus:status];
- }
+ if ([self.class isVisible]) {
+ [UIView animateWithDuration:KVNLayoutAnimationDuration
+ animations:^{
+ [self setupStatus:status];
+ }];
+ } else {
+ [self setupStatus:status];
+ }
}
- (void)updateStatusConstraints
{
- BOOL showStatus = (self.status.length > 0);
-
- self.circleProgressViewToStatusLabelVerticalSpaceConstraint.constant = (showStatus) ? KVNCircleProgressViewToStatusLabelVerticalSpaceConstraintConstant : 0.0f;
-
- CGSize maximumLabelSize = CGSizeMake(CGRectGetWidth(self.statusLabel.bounds), CGFLOAT_MAX);
- CGSize statusLabelSize = [self.statusLabel sizeThatFits:maximumLabelSize];
- self.statusLabelHeightConstraint.constant = statusLabelSize.height;
-
- [self layoutIfNeeded];
+ BOOL showStatus = (self.status.length > 0);
+
+ self.circleProgressViewToStatusLabelVerticalSpaceConstraint.constant = (showStatus) ? KVNCircleProgressViewToStatusLabelVerticalSpaceConstraintConstant : 0.0f;
+
+ CGSize maximumLabelSize = CGSizeMake(CGRectGetWidth(self.statusLabel.bounds), CGFLOAT_MAX);
+ CGSize statusLabelSize = [self.statusLabel sizeThatFits:maximumLabelSize];
+ self.statusLabelHeightConstraint.constant = statusLabelSize.height;
+
+ [self layoutIfNeeded];
}
+ (void)updateProgress:(CGFloat)progress
- animated:(BOOL)animated
+ animated:(BOOL)animated
{
- [[self sharedView] updateProgress:progress
- animated:animated];
+ dispatch_async([self sharedView].queue, ^{
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ [[self sharedView] updateProgress:progress
+ animated:animated];
+ });
+ });
}
- (void)updateProgress:(CGFloat)progress
- animated:(BOOL)animated
-{
- if (self.style != KVNProgressStyleProgress) {
- return;
- }
-
- if ([self isIndeterminate]) {
- // was inderminate
- [self showProgress:progress
- status:self.status
- style:self.style
- backgroundType:self.backgroundType
- fullScreen:self.fullScreen
- view:self.superview
- completion:nil];
-
- return;
- }
-
- // Boundry correctness
- progress = MIN(progress, 1.0f);
- progress = MAX(progress, 0.0f);
-
- if (animated) {
- CABasicAnimation *progressAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
-
- progressAnimation.duration = KVNProgressAnimationDuration;
- progressAnimation.removedOnCompletion = NO;
- progressAnimation.fillMode = kCAFillModeBoth;
- progressAnimation.fromValue = @(self.progress);
- progressAnimation.toValue = @(progress);
- progressAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
-
- [self.circleProgressLineLayer addAnimation:progressAnimation
- forKey:@"strokeEnd"];
- } else {
- self.circleProgressLineLayer.strokeEnd = progress;
- }
-
- self.progress = progress;
+ animated:(BOOL)animated
+{
+ if (self.style != KVNProgressStyleProgress) {
+ return;
+ }
+
+ if ([self isIndeterminate]) {
+ // was inderminate
+ [self showProgress:progress
+ status:self.status
+ style:self.style
+ backgroundType:self.backgroundType
+ fullScreen:self.fullScreen
+ view:self.superview
+ completion:nil];
+
+ return;
+ }
+
+ // Boundry correctness
+ progress = MIN(progress, 1.0f);
+ progress = MAX(progress, 0.0f);
+
+ if (animated) {
+ CABasicAnimation *progressAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+
+ progressAnimation.duration = KVNProgressAnimationDuration;
+ progressAnimation.removedOnCompletion = NO;
+ progressAnimation.fillMode = kCAFillModeBoth;
+ progressAnimation.fromValue = @(self.progress);
+ progressAnimation.toValue = @(progress);
+ progressAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+
+ [self.circleProgressLineLayer addAnimation:progressAnimation
+ forKey:@"strokeEnd"];
+ } else {
+ self.circleProgressLineLayer.strokeEnd = progress;
+ }
+
+ self.progress = progress;
}
#pragma mark - Animations
- (void)animateUI
{
- switch (self.style) {
- case KVNProgressStyleProgress: {
- if ([self isIndeterminate]) {
- [self setupInfiniteCircle];
- } else {
- [self setupProgressCircle];
- }
-
- break;
- }
- case KVNProgressStyleSuccess: {
- [self setupSuccessUI];
- break;
- }
- case KVNProgressStyleError: {
- [self setupErrorUI];
- break;
- }
- case KVNProgressStyleHidden: {
- // should enver happen
- break;
- }
- }
+ switch (self.style) {
+ case KVNProgressStyleProgress: {
+ if ([self isIndeterminate]) {
+ [self setupInfiniteCircle];
+ } else {
+ [self setupProgressCircle];
+ }
+
+ break;
+ }
+ case KVNProgressStyleSuccess: {
+ [self setupSuccessUI];
+ break;
+ }
+ case KVNProgressStyleError: {
+ [self setupErrorUI];
+ break;
+ }
+ case KVNProgressStyleHidden: {
+ // should enver happen
+ break;
+ }
+ }
}
- (void)animateAppearance
{
- [UIView animateWithDuration:0.0f
- delay:0.0f
- options:UIViewAnimationOptionBeginFromCurrentState
- animations:^{}
- completion:nil];
-
- self.alpha = 0.0f;
- self.contentView.transform = CGAffineTransformScale(self.contentView.transform, 1.2f, 1.2f);
-
- self.showActionTrigerredDate = [NSDate date];
-
- KVNPrepareBlockSelf();
- [UIView animateWithDuration:KVNFadeAnimationDuration
- delay:0.0f
- options:UIViewAnimationOptionCurveEaseOut
- animations:^{
- KVNBlockSelf.alpha = 1.0f;
- KVNBlockSelf.contentView.transform = CGAffineTransformIdentity;
- } completion:^(BOOL finished) {
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
- UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, self.status);
-
- KVNBlockSelf.state = KVNProgressStateShowed;
- }];
+ [UIView animateWithDuration:0.0f
+ delay:0.0f
+ options:UIViewAnimationOptionBeginFromCurrentState
+ animations:^{}
+ completion:nil];
+
+ self.alpha = 0.0f;
+ self.contentView.transform = CGAffineTransformScale(self.contentView.transform, 1.2f, 1.2f);
+
+ self.showActionTrigerredDate = [NSDate date];
+
+ KVNPrepareBlockSelf();
+ [UIView animateWithDuration:KVNFadeAnimationDuration
+ delay:0.0f
+ options:UIViewAnimationOptionCurveEaseOut
+ animations:^{
+ KVNBlockSelf.alpha = 1.0f;
+ KVNBlockSelf.contentView.transform = CGAffineTransformIdentity;
+ } completion:^(BOOL finished) {
+ UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
+ UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, KVNBlockSelf.status);
+
+ // Notify the show block that the appearance animation is completed.
+ KVNProgress *strongSelf = KVNBlockSelf;
+ if (strongSelf) {
+ dispatch_semaphore_signal(strongSelf.semaphore);
+ }
+ }];
}
- (void)animateCircleWithInfiniteLoop
{
- CABasicAnimation* rotationAnimation;
- rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
- rotationAnimation.toValue = @(M_PI * 2.0f * KVNInfiniteLoopAnimationDuration);
- rotationAnimation.duration = KVNInfiniteLoopAnimationDuration;
- rotationAnimation.cumulative = YES;
- rotationAnimation.repeatCount = HUGE_VALF;
-
- [self.circleProgressView.layer addAnimation:rotationAnimation
- forKey:@"rotationAnimation"];
+ CABasicAnimation* rotationAnimation;
+ rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
+ rotationAnimation.toValue = @(M_PI * 2.0f * KVNInfiniteLoopAnimationDuration);
+ rotationAnimation.duration = KVNInfiniteLoopAnimationDuration;
+ rotationAnimation.cumulative = YES;
+ rotationAnimation.repeatCount = HUGE_VALF;
+
+ [self.circleProgressView.layer addAnimation:rotationAnimation
+ forKey:@"rotationAnimation"];
}
- (void)cancelCircleAnimation
{
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
-
- [self.circleProgressView.layer removeAllAnimations];
- [self.circleProgressLineLayer removeAllAnimations];
- [self.circleBackgroundLineLayer removeAllAnimations];
-
- self.circleProgressLineLayer.strokeEnd = 0.0f;
- self.circleBackgroundLineLayer.strokeEnd = 0.0f;
-
- if (self.circleProgressLineLayer.superlayer) {
- [self.circleProgressLineLayer removeFromSuperlayer];
- }
- if (self.circleBackgroundLineLayer.superlayer) {
- [self.circleBackgroundLineLayer removeFromSuperlayer];
- }
-
- self.circleProgressLineLayer = nil;
- self.circleBackgroundLineLayer = nil;
-
- [CATransaction commit];
+ [CATransaction begin];
+ [CATransaction setDisableActions:YES];
+
+ [self.circleProgressView.layer removeAllAnimations];
+ [self.circleProgressLineLayer removeAllAnimations];
+ [self.circleBackgroundLineLayer removeAllAnimations];
+
+ self.circleProgressLineLayer.strokeEnd = 0.0f;
+ self.circleBackgroundLineLayer.strokeEnd = 0.0f;
+
+ if (self.circleProgressLineLayer.superlayer) {
+ [self.circleProgressLineLayer removeFromSuperlayer];
+ }
+ if (self.circleBackgroundLineLayer.superlayer) {
+ [self.circleBackgroundLineLayer removeFromSuperlayer];
+ }
+
+ self.circleProgressLineLayer = nil;
+ self.circleBackgroundLineLayer = nil;
+
+ [CATransaction commit];
}
- (void)animateSuccess
{
- [self animateFullCircleWithColor:self.configuration.successColor];
-
- CABasicAnimation *checkmarkAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
- checkmarkAnimation.duration = KVNCheckmarkAnimationDuration;
- checkmarkAnimation.removedOnCompletion = NO;
- checkmarkAnimation.fillMode = kCAFillModeBoth;
- checkmarkAnimation.fromValue = @(0);
- checkmarkAnimation.toValue = @(1);
- checkmarkAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
-
- [self.checkmarkLayer addAnimation:checkmarkAnimation
- forKey:@"strokeEnd"];
+ [self animateFullCircleWithColor:self.configuration.successColor];
+
+ CABasicAnimation *checkmarkAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ checkmarkAnimation.duration = KVNCheckmarkAnimationDuration;
+ checkmarkAnimation.removedOnCompletion = NO;
+ checkmarkAnimation.fillMode = kCAFillModeBoth;
+ checkmarkAnimation.fromValue = @(0);
+ checkmarkAnimation.toValue = @(1);
+ checkmarkAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
+
+ [self.checkmarkLayer addAnimation:checkmarkAnimation
+ forKey:@"strokeEnd"];
}
- (void)animateError
{
- [self animateFullCircleWithColor:self.configuration.errorColor];
+ [self animateFullCircleWithColor:self.configuration.errorColor];
}
- (void)animateFullCircleWithColor:(UIColor *)color
{
- CABasicAnimation *circleAnimation;
- if (self.superview) {
- circleAnimation = [CABasicAnimation animationWithKeyPath:@"strokeColor"];
- circleAnimation.duration = KVNCheckmarkAnimationDuration;
- circleAnimation.toValue = (id)color.CGColor;
- circleAnimation.fillMode = kCAFillModeBoth;
- circleAnimation.removedOnCompletion = NO;
- } else {
- circleAnimation = [CABasicAnimation animationWithKeyPath:@"alpha"];
- circleAnimation.duration = KVNCheckmarkAnimationDuration;
- circleAnimation.fromValue = @(0);
- circleAnimation.toValue = @(1);
- circleAnimation.fillMode = kCAFillModeBoth;
- circleAnimation.removedOnCompletion = NO;
- }
-
- [self.circleProgressLineLayer addAnimation:circleAnimation
- forKey:@"appearance"];
+ CABasicAnimation *circleAnimation;
+ if (self.superview) {
+ circleAnimation = [CABasicAnimation animationWithKeyPath:@"strokeColor"];
+ circleAnimation.duration = KVNCheckmarkAnimationDuration;
+ circleAnimation.toValue = (id)color.CGColor;
+ circleAnimation.fillMode = kCAFillModeBoth;
+ circleAnimation.removedOnCompletion = NO;
+ } else {
+ circleAnimation = [CABasicAnimation animationWithKeyPath:@"alpha"];
+ circleAnimation.duration = KVNCheckmarkAnimationDuration;
+ circleAnimation.fromValue = @(0);
+ circleAnimation.toValue = @(1);
+ circleAnimation.fillMode = kCAFillModeBoth;
+ circleAnimation.removedOnCompletion = NO;
+ }
+
+ [self.circleProgressLineLayer addAnimation:circleAnimation
+ forKey:@"appearance"];
}
#pragma mark - Helpers
- (void)removeAllSubLayersOfLayer:(CALayer *)layer
{
- for (CALayer *subLayer in [layer.sublayers copy]) {
- // Technical :
- // we use a copy of self.circleProgressView.layer.sublayers because this array will
- // change when we remove its sublayers
- [subLayer removeFromSuperlayer];
- }
+ for (CALayer *subLayer in [layer.sublayers copy]) {
+ // Technical :
+ // we use a copy of self.circleProgressView.layer.sublayers because this array will
+ // change when we remove its sublayers
+ [subLayer removeFromSuperlayer];
+ }
}
- (UIImage *)blurredScreenShot
{
- return [self blurredScreenShotWithRect:[UIApplication sharedApplication].keyWindow.frame];
+ return [self blurredScreenShotWithRect:[UIApplication sharedApplication].keyWindow.frame];
}
- (UIImage *)blurredScreenShotWithRect:(CGRect)rect
{
- UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
-
- UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
-
- [keyWindow drawViewHierarchyInRect:rect afterScreenUpdates:NO];
- UIImage *blurredScreenShot = UIGraphicsGetImageFromCurrentImageContext();
-
- UIGraphicsEndImageContext();
-
- blurredScreenShot = [self applyTintEffectWithColor:self.configuration.backgroundTintColor
- image:blurredScreenShot];
-
- return blurredScreenShot;
+ UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
+
+ UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
+
+ [keyWindow drawViewHierarchyInRect:rect afterScreenUpdates:NO];
+ UIImage *blurredScreenShot = UIGraphicsGetImageFromCurrentImageContext();
+
+ UIGraphicsEndImageContext();
+
+ blurredScreenShot = [self applyTintEffectWithColor:self.configuration.backgroundTintColor
+ image:blurredScreenShot];
+
+ return blurredScreenShot;
}
- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor
- image:(UIImage *)image
-{
- const CGFloat EffectColorAlpha = 0.6;
- UIColor *effectColor = tintColor;
- int componentCount = (int)CGColorGetNumberOfComponents(tintColor.CGColor);
- CGFloat tintAlpha = CGColorGetAlpha(tintColor.CGColor);
-
- if (tintAlpha == 0.0f) {
- return [image applyBlurWithRadius:10.0f
- tintColor:nil
- saturationDeltaFactor:1.0f
- maskImage:nil];
- }
-
- if (componentCount == 2) {
- CGFloat b;
- if ([tintColor getWhite:&b alpha:NULL]) {
- effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha];
- }
- }
- else {
- CGFloat r, g, b;
- if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) {
- effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha];
- }
- }
-
- return [image applyBlurWithRadius:10.0f
- tintColor:effectColor
- saturationDeltaFactor:1.0f
- maskImage:nil];
+ image:(UIImage *)image
+{
+ const CGFloat EffectColorAlpha = 0.6;
+ UIColor *effectColor = tintColor;
+ int componentCount = (int)CGColorGetNumberOfComponents(tintColor.CGColor);
+ CGFloat tintAlpha = CGColorGetAlpha(tintColor.CGColor);
+
+ if (tintAlpha == 0.0f) {
+ return [image applyBlurWithRadius:10.0f
+ tintColor:nil
+ saturationDeltaFactor:1.0f
+ maskImage:nil];
+ }
+
+ if (componentCount == 2) {
+ CGFloat b;
+ if ([tintColor getWhite:&b alpha:NULL]) {
+ effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha];
+ }
+ }
+ else {
+ CGFloat r, g, b;
+ if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) {
+ effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha];
+ }
+ }
+
+ return [image applyBlurWithRadius:10.0f
+ tintColor:effectColor
+ saturationDeltaFactor:1.0f
+ maskImage:nil];
}
- (UIImage *)cropImage:(UIImage *)image
- rect:(CGRect)cropRect
+ rect:(CGRect)cropRect
{
- // Create bitmap image from original image data,
- // using rectangle to specify desired crop area
- CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);
- image = [UIImage imageWithCGImage:imageRef];
- CGImageRelease(imageRef);
-
- return image;
+ // Create bitmap image from original image data,
+ // using rectangle to specify desired crop area
+ CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);
+ image = [UIImage imageWithCGImage:imageRef];
+ CGImageRelease(imageRef);
+
+ return image;
}
- (UIInterpolatingMotionEffect *)motionEffectWithType:(UIInterpolatingMotionEffectType)motionEffectType
- keyPath:(NSString *)keypath
+ keyPath:(NSString *)keypath
{
- UIInterpolatingMotionEffect *motionEffect = [[UIInterpolatingMotionEffect alloc]
- initWithKeyPath:keypath
- type:motionEffectType];
- motionEffect.minimumRelativeValue = @(-KVNMotionEffectRelativeValue);
- motionEffect.maximumRelativeValue = @(KVNMotionEffectRelativeValue);
-
- return motionEffect;
+ UIInterpolatingMotionEffect *motionEffect = [[UIInterpolatingMotionEffect alloc]
+ initWithKeyPath:keypath
+ type:motionEffectType];
+ motionEffect.minimumRelativeValue = @(-KVNMotionEffectRelativeValue);
+ motionEffect.maximumRelativeValue = @(KVNMotionEffectRelativeValue);
+
+ return motionEffect;
}
- (CGFloat)rotationForStatusBarOrientation {
- switch ([UIApplication sharedApplication].statusBarOrientation) {
- case UIInterfaceOrientationLandscapeLeft:
- return -M_PI_2;
- case UIInterfaceOrientationLandscapeRight:
- return M_PI_2;
- case UIInterfaceOrientationPortraitUpsideDown:
- return M_PI;
- case UIInterfaceOrientationPortrait:
- case UIInterfaceOrientationUnknown:
- return 0;
- }
+ switch ([UIApplication sharedApplication].statusBarOrientation) {
+ case UIInterfaceOrientationLandscapeLeft:
+ return -M_PI_2;
+ case UIInterfaceOrientationLandscapeRight:
+ return M_PI_2;
+ case UIInterfaceOrientationPortraitUpsideDown:
+ return M_PI;
+ case UIInterfaceOrientationPortrait:
+ case UIInterfaceOrientationUnknown:
+ return 0;
+ }
}
- (CGRect)correctedBounds
{
- return [self correctedBoundsForBounds:self.bounds];
+ return [self correctedBoundsForBounds:self.bounds];
}
- (CGRect)correctedBoundsForBounds:(CGRect)boundsToCorrect
{
- CGRect bounds = (CGRect){CGPointZero, boundsToCorrect.size};
-
- if (!KVNSystemVersionGreaterOrEqual_iOS_8 && [self.superview isKindOfClass:UIWindow.class])
- {
- // landscape orientation but width is smaller than height
- // or portrait orientation but width is larger than height
- if ((UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)
- && CGRectGetWidth(bounds) < CGRectGetHeight(bounds))
- || (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)
- && CGRectGetWidth(bounds) > CGRectGetHeight(bounds))) {
- bounds = (CGRect){CGPointZero, {bounds.size.height, bounds.size.width}};
- }
- }
-
- return bounds;
+ CGRect bounds = (CGRect){CGPointZero, boundsToCorrect.size};
+
+ if (!KVNSystemVersionGreaterOrEqual_iOS_8 && [self.superview isKindOfClass:UIWindow.class])
+ {
+ // landscape orientation but width is smaller than height
+ // or portrait orientation but width is larger than height
+ if ((UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)
+ && CGRectGetWidth(bounds) < CGRectGetHeight(bounds))
+ || (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)
+ && CGRectGetWidth(bounds) > CGRectGetHeight(bounds))) {
+ bounds = (CGRect){CGPointZero, {bounds.size.height, bounds.size.width}};
+ }
+ }
+
+ return bounds;
}
#pragma mark - Configuration
+ (KVNProgressConfiguration *)configuration
{
- return configuration;
+ return configuration;
}
+ (void)setConfiguration:(KVNProgressConfiguration *)newConfiguration
{
- configuration = newConfiguration;
- [self sharedView].configuration = configuration;
+ configuration = newConfiguration;
+ [self sharedView].configuration = configuration;
}
#pragma mark - Information
- (BOOL)isIndeterminate
{
- return (self.progress == KVNProgressIndeterminate);
+ return (self.progress == KVNProgressIndeterminate);
}
+ (BOOL)isVisible
{
- return ([self sharedView].superview != nil && [self sharedView].alpha > 0.0f);
+ return ([self sharedView].superview != nil && [self sharedView].alpha > 0.0f);
}
#pragma mark - Tap Block
- (void)performTapBlock {
- if (self.configuration.tapBlock) {
- KVNPrepareBlockSelf();
- self.configuration.tapBlock(KVNBlockSelf);
- }
+ if (self.configuration.tapBlock) {
+ KVNPrepareBlockSelf();
+ self.configuration.tapBlock(KVNBlockSelf);
+ }
}
#pragma mark - HitTest
@@ -1275,11 +1319,11 @@ - (void)performTapBlock {
// Used to block interaction for all views behind
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
- if (self.configuration.allowUserInteraction && ![self isFullScreen]) {
- return nil;
- } else {
- return (CGRectContainsPoint(self.frame, point)) ? self : nil;
- }
+ if (self.configuration.allowUserInteraction && ![self isFullScreen]) {
+ return nil;
+ } else {
+ return (CGRectContainsPoint(self.frame, point)) ? self : nil;
+ }
}
-@end
+@end
\ No newline at end of file
diff --git a/KVNProgress/KVNProgress-Info.plist b/KVNProgress/KVNProgress-Info.plist
index 030bd17..2efc3ec 100644
--- a/KVNProgress/KVNProgress-Info.plist
+++ b/KVNProgress/KVNProgress-Info.plist
@@ -21,7 +21,7 @@
CFBundleSignature
????
CFBundleVersion
- 132
+ 150
LSRequiresIPhoneOS
UIMainStoryboardFile