From 450ba358ed635fc24695d18e9617076140179aef Mon Sep 17 00:00:00 2001 From: Artem Starosvetskiy Date: Fri, 6 Jul 2018 16:15:45 +0300 Subject: [PATCH 1/9] Improve coding style. --- .../Views/MONActivityIndicatorView/MONActivityIndicatorView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m index 364719f..0ab2fe0 100644 --- a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m +++ b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m @@ -130,7 +130,7 @@ - (void)addCircles { color = [self.delegate activityIndicatorView:self circleBackgroundColorAtIndex:i]; } UIView *circle = [self createCircleWithRadius:self.radius - color:(color == nil) ? self.defaultColor : color + color:color ?: self.defaultColor positionX:(i * ((2 * self.radius) + self.internalSpacing))]; [circle setTransform:CGAffineTransformMakeScale(0, 0)]; [circle.layer addAnimation:[self createAnimationWithDuration:self.duration delay:(i * self.delay)] forKey:@"scale"]; From 70c3d54215845c9bf441deedf356443e324cf377 Mon Sep 17 00:00:00 2001 From: Artem Starosvetskiy Date: Fri, 6 Jul 2018 16:18:36 +0300 Subject: [PATCH 2/9] Rename some arguments. --- .../Views/MONActivityIndicatorView/MONActivityIndicatorView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m index 0ab2fe0..7ef0245 100644 --- a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m +++ b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m @@ -139,8 +139,8 @@ - (void)addCircles { } - (void)removeCircles { - [self.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [obj removeFromSuperview]; + [self.subviews enumerateObjectsUsingBlock:^(UIView *circle, NSUInteger index, BOOL *stop) { + [circle removeFromSuperview]; }]; } From 5d12a24905dba941ad4164b6ffbc2119f94a35d7 Mon Sep 17 00:00:00 2001 From: Artem Starosvetskiy Date: Fri, 6 Jul 2018 17:14:57 +0300 Subject: [PATCH 3/9] Use property syntax where it's appropriate. --- .../Views/MONActivityIndicatorView/MONActivityIndicatorView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m index 7ef0245..b51c84d 100644 --- a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m +++ b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m @@ -132,7 +132,7 @@ - (void)addCircles { UIView *circle = [self createCircleWithRadius:self.radius color:color ?: self.defaultColor positionX:(i * ((2 * self.radius) + self.internalSpacing))]; - [circle setTransform:CGAffineTransformMakeScale(0, 0)]; + circle.transform = CGAffineTransformMakeScale(0, 0); [circle.layer addAnimation:[self createAnimationWithDuration:self.duration delay:(i * self.delay)] forKey:@"scale"]; [self addSubview:circle]; } From 2250c4404ec3e7c9d4420ec5b5b52b8b817fd251 Mon Sep 17 00:00:00 2001 From: Artem Starosvetskiy Date: Fri, 6 Jul 2018 20:53:43 +0300 Subject: [PATCH 4/9] Restart animations after an indicator view is added to a window. --- .../MONActivityIndicatorView.m | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m index b51c84d..69208ea 100644 --- a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m +++ b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m @@ -87,6 +87,19 @@ - (CGSize)intrinsicContentSize { return CGSizeMake(width, height); } +#pragma mark - +#pragma mark - View Lifecycle + +- (void)didMoveToWindow { + [super didMoveToWindow]; + + // Core Animation animations are removed when the view is remove from a window. + // So, we have to add the animations again when the view is added to a window. + if (self.window && self.isAnimating) { + [self addCircleAnimations]; + } +} + #pragma mark - #pragma mark - Private Methods @@ -133,9 +146,12 @@ - (void)addCircles { color:color ?: self.defaultColor positionX:(i * ((2 * self.radius) + self.internalSpacing))]; circle.transform = CGAffineTransformMakeScale(0, 0); - [circle.layer addAnimation:[self createAnimationWithDuration:self.duration delay:(i * self.delay)] forKey:@"scale"]; [self addSubview:circle]; } + + if (self.window) { + [self addCircleAnimations]; + } } - (void)removeCircles { @@ -144,6 +160,12 @@ - (void)removeCircles { }]; } +- (void)addCircleAnimations { + [self.subviews enumerateObjectsUsingBlock:^(UIView *circle, NSUInteger index, BOOL *stop) { + [circle.layer addAnimation:[self createAnimationWithDuration:self.duration delay:(index * self.delay)] forKey:@"scale"]; + }]; +} + #pragma mark - #pragma mark - Public Methods From ffb21459d3709795f75d95d2b3200092a8d10815 Mon Sep 17 00:00:00 2001 From: Artem Starosvetskiy Date: Fri, 6 Jul 2018 20:59:18 +0300 Subject: [PATCH 5/9] Add a method declaration according to the coding style. --- .../MONActivityIndicatorView/MONActivityIndicatorView.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m index 69208ea..e07d08f 100644 --- a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m +++ b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m @@ -30,6 +30,11 @@ - (void)addCircles; */ - (void)removeCircles; +/** + Add animations to the circle layers. + */ +- (void)addCircleAnimations; + /** Creates the circle view. @param radius The radius of the circle. From be473931ac6506ad73f7878cc4713453c8cd73ca Mon Sep 17 00:00:00 2001 From: Artem Starosvetskiy Date: Fri, 6 Jul 2018 21:06:17 +0300 Subject: [PATCH 6/9] Fix a typo. --- .../Views/MONActivityIndicatorView/MONActivityIndicatorView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m index e07d08f..7fcf780 100644 --- a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m +++ b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m @@ -31,7 +31,7 @@ - (void)addCircles; - (void)removeCircles; /** - Add animations to the circle layers. + Adds animations to the circle layers. */ - (void)addCircleAnimations; From 001134496a177152498cce09e295507eed5335fc Mon Sep 17 00:00:00 2001 From: Artem Starosvetskiy Date: Fri, 6 Jul 2018 21:32:10 +0300 Subject: [PATCH 7/9] Unify API with `UIActivityIndicatorView`: rename the `animating` property and expose it to public API. --- .../MONActivityIndicatorView.h | 2 ++ .../MONActivityIndicatorView.m | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.h b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.h index 47903a0..dda898a 100644 --- a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.h +++ b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.h @@ -37,6 +37,8 @@ FOUNDATION_EXPORT const unsigned char MONActivityIndicatorViewVersionString[]; /** The assigned delegate */ @property (weak, nonatomic) id delegate; +/** Indicates whether the activity indicator view is animating. */ +@property (readonly, nonatomic, getter=isAnimating) BOOL animating; /** Starts the animation of the activity indicator. diff --git a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m index 7fcf780..b37d87e 100644 --- a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m +++ b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m @@ -12,8 +12,8 @@ @interface MONActivityIndicatorView () /** The default color of each circle. */ @property (strong, nonatomic) UIColor *defaultColor; -/** An indicator whether the activity indicator view is animating. */ -@property (readwrite, nonatomic) BOOL isAnimating; +/** Indicates whether the activity indicator view is animating. */ +@property (readwrite, nonatomic, getter=isAnimating) BOOL animating; /** Sets up default values @@ -100,7 +100,7 @@ - (void)didMoveToWindow { // Core Animation animations are removed when the view is remove from a window. // So, we have to add the animations again when the view is added to a window. - if (self.window && self.isAnimating) { + if (self.window && self.animating) { [self addCircleAnimations]; } } @@ -175,18 +175,18 @@ - (void)addCircleAnimations { #pragma mark - Public Methods - (void)startAnimating { - if (!self.isAnimating) { + if (!self.animating) { [self addCircles]; self.hidden = NO; - self.isAnimating = YES; + self.animating = YES; } } - (void)stopAnimating { - if (self.isAnimating) { + if (self.animating) { [self removeCircles]; self.hidden = YES; - self.isAnimating = NO; + self.animating = NO; } } From 2b88af6dd8b2d21e1ec6927b396b58193f27b75d Mon Sep 17 00:00:00 2001 From: Artem Starosvetskiy Date: Sat, 7 Jul 2018 01:08:15 +0300 Subject: [PATCH 8/9] Stop animating when `UITableViewCell` or `UICollectionViewCell` remove all animations. --- .../MONActivityIndicatorView.m | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m index b37d87e..5a27fd4 100644 --- a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m +++ b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m @@ -7,6 +7,31 @@ #import #import "MONActivityIndicatorView.h" +@interface MONActivityIndicatorLayer : CALayer + +@property (nonatomic, weak, readonly) MONActivityIndicatorView *view; + +@end + +@implementation MONActivityIndicatorLayer + +- (MONActivityIndicatorView *)view { + return (MONActivityIndicatorView *)self.delegate; +} + +- (void)removeAllAnimations { + [super removeAllAnimations]; + + // `-[UITableViewCell prepareForReuse]` and `-[UICollectionViewCell prepareForReuse]` remove all animations from + // child views. There is no way to restart animations automatically (as we do it in `-didMoveToWindow`). + // So, we have to stop animating. + // Note: We can't do it in `-animationDidStop:finished:` animation delegate, because the delegate method is called + // asynchronously. + [self.view stopAnimating]; +} + +@end + @interface MONActivityIndicatorView () /** The default color of each circle. */ @@ -84,7 +109,11 @@ - (id)initWithCoder:(NSCoder *)aDecoder { } #pragma mark - -#pragma mark - Intrinsic Content Size +#pragma mark - UIViews + ++ (Class)layerClass { + return [MONActivityIndicatorLayer class]; +} - (CGSize)intrinsicContentSize { CGFloat width = (self.numberOfCircles * ((2 * self.radius) + self.internalSpacing)) - self.internalSpacing; @@ -92,9 +121,6 @@ - (CGSize)intrinsicContentSize { return CGSizeMake(width, height); } -#pragma mark - -#pragma mark - View Lifecycle - - (void)didMoveToWindow { [super didMoveToWindow]; From eeb63e3913bb9e5eca25e33480e85da5d7264cfe Mon Sep 17 00:00:00 2001 From: Artem Starosvetskiy Date: Fri, 27 Jul 2018 15:22:50 +0300 Subject: [PATCH 9/9] Support manual layout. --- .../Views/MONActivityIndicatorView/MONActivityIndicatorView.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m index 5a27fd4..81401ae 100644 --- a/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m +++ b/MONActivityIndicatorViewDemo/MONActivityIndicatorViewDemo/Source/Views/MONActivityIndicatorView/MONActivityIndicatorView.m @@ -121,6 +121,10 @@ - (CGSize)intrinsicContentSize { return CGSizeMake(width, height); } +- (CGSize)sizeThatFits:(CGSize)size { + return self.intrinsicContentSize; +} + - (void)didMoveToWindow { [super didMoveToWindow];