Commits

Joris Kluivers committed 5e9a0b1

Optimized reconfiguration code, to only update once per runloop (after multiple configuration changes in one runloop cycle for example)

Comments (0)

Files changed (2)

JKActivityIndicatorView.h

 
 @property(readonly) BOOL isAnimating;
 
+/* Set styles to match a UIKit indicator style */
+- (void) setStyle:(UIActivityIndicatorViewStyle)indicatorStyle;
+
 - (void) startAnimating;
 
 @end

JKActivityIndicatorView.m

 
 @interface JKActivityIndicatorView ()
 
-@property(nonatomic, assign, getter=hasConfigurationChanged) BOOL configurationChanged;
+@property(nonatomic, assign, getter=didConfigurationChange) BOOL configurationChanged;
+@property(nonatomic, assign, getter=didNumberOfLinesChange) BOOL numberOfLinesChanged;
 
 /* Array of calayers, representing lines */
 @property(nonatomic, retain) NSArray *lines;
 /*! Configures all layers to display a indicator view. */
 - (void) configureIndicator;
 
+/*! Method to indicate the configuration has changed and needs updating. Multiple calls
+ * will only perform one configuration. Updating multiple properties will thus only 
+ * reconfigure the indicator once
+ */
+- (void) setNeedsConfiguration;
+
+- (void) applyStylesToLine:(CALayer *)line;
+
 @end
 
 
 @synthesize numberOfLines, lineLength, lineWidth, radius, trail, speed, isAnimating;
 
 /* Private properties */
-@synthesize configurationChanged, lines;
+@synthesize configurationChanged, numberOfLinesChanged, lines;
 
 // MARK: - View management
 
 
 - (void) dealloc {
     self.lines = nil;
+    [NSThread cancelPreviousPerformRequestsWithTarget:self];
     
     [super dealloc];
 }
 }
 
 - (void) configureIndicator {
-    for (CALayer *l in self.lines) {
-        [l removeFromSuperlayer];
+    NSLog(@"%s", __func__);
+    
+    if (self.didNumberOfLinesChange) {
+        // recreate lines
+        
+        for (CALayer *l in self.lines) {
+            [l removeFromSuperlayer];
+        }
+        
+        NSMutableArray *newLines = [NSMutableArray array];
+        for (NSInteger i=0; i<self.numberOfLines; i++) {
+            CALayer *line = [CALayer layer];
+            [self.layer addSublayer:line];
+            [newLines addObject:line];
+        }
+        self.lines = newLines;
     }
     
-    CGFloat angle = (M_PI * 2) / self.numberOfLines;
+    // apply styles to lines
+    CGFloat currentAngle = - M_PI/2;
+    CGFloat angleDelta = (M_PI * 2) / self.numberOfLines;
     
-    NSMutableArray *newLines = [NSMutableArray array];
-    for (NSInteger i=0; i<self.numberOfLines; i++) {
+    for (CALayer *line in self.lines) {
+        [self applyStylesToLine:line];
         
-        CALayer *line = [CALayer layer];
-        [self.layer addSublayer:line];
-        
-        line.backgroundColor = [UIColor whiteColor].CGColor;
         line.anchorPoint = CGPointMake(0.0f, 0.5f);
         
-        CGSize lineSize = CGSizeMake(self.lineWidth + self.lineLength, self.lineWidth);
-        line.frame = (CGRect) {.size=lineSize};
-        line.cornerRadius = self.lineWidth / 2;
-        
-        //CATransform3D transform = CATransform3DMakeTranslation(self.radius, 0.0f, 0.0f);
-        //transform = CATransform3DRotate(transform, angle*i, 0.0f, 0.0f, 1.0f);
-        CGFloat lineAngle = angle * i;
-        
-        // angle minus M_PI/2 to start at 0,1 instead of 1,0
-        CATransform3D transform = CATransform3DMakeRotation(-lineAngle - (M_PI/2), 0.0f, 0.0f, 1.0f);
+        CATransform3D transform = CATransform3DMakeRotation(currentAngle, 0.0f, 0.0f, 1.0f);
         transform = CATransform3DTranslate(transform, self.radius, 0.0f, 0.0f);
         line.transform = transform;
         
-        CGFloat opacity = 1.0f - (1.0f - kDimmedOpacity) * MIN(1.0f, (lineAngle / (M_PI*2*self.trail)));
+        CGFloat opacity = 1.0f - (1.0f - kDimmedOpacity) * MIN(1.0f, (currentAngle / (M_PI*2*self.trail)));
         line.opacity = opacity;
         
-        
-        [newLines addObject:line];
+        currentAngle += angleDelta;
     }
     
     self.layer.shadowColor = [UIColor blackColor].CGColor;
     self.layer.shadowRadius = 2.0f;
     self.layer.shadowOpacity = 0.8f;
     
-    self.lines = newLines;
-    
     if (self.isAnimating) {
         [self addAnimations];
     }
+    
+    self.configurationChanged = NO;
+}
+
+- (void) applyStylesToLine:(CALayer *)line {
+    line.backgroundColor = [UIColor whiteColor].CGColor;
+    
+    CGSize lineSize = CGSizeMake(self.lineWidth + self.lineLength, self.lineWidth);
+    line.frame = (CGRect) {.size=lineSize};
+    line.cornerRadius = self.lineWidth / 2;
+}
+
+- (void) setNeedsConfiguration {
+    if (self.didConfigurationChange) {
+        return;
+    }
+    
+    [self performSelector:@selector(configureIndicator) withObject:nil afterDelay:0.0f];
+    
+    self.configurationChanged = YES;
 }
 
 // MARK: - Custom setters
 - (void) setNumberOfLines:(NSInteger)newNumberOfLines {
     numberOfLines = newNumberOfLines;
     
-    self.configurationChanged = YES;
-    [self setNeedsLayout];
+    self.numberOfLinesChanged = YES;
+    [self setNeedsConfiguration];
 }
 
 - (void) setLineLength:(CGFloat)newLength {
     lineLength = newLength;
     
-    self.configurationChanged = YES;
-    [self setNeedsLayout];
+    [self setNeedsConfiguration];
 }
 
 - (void) setLineWidth:(CGFloat)newWidth {
     lineWidth = newWidth;
     
-    self.configurationChanged = YES;
-    [self setNeedsLayout];
+    [self setNeedsConfiguration];
 }
 
 - (void) setRadius:(CGFloat)newRadius {
     radius = newRadius;
     
-    self.configurationChanged = YES;
-    [self setNeedsLayout];
+    [self setNeedsConfiguration];
 }
 
 - (void) setTrail:(CGFloat)newTrail {
     trail = newTrail;
     
-    self.configurationChanged = YES;
-    [self setNeedsLayout];
+    [self setNeedsConfiguration];
 }
 
 - (void) setSpeed:(CGFloat)newSpeed {
     speed = newSpeed;
     
-    self.configurationChanged = YES;
-    [self setNeedsLayout];
+    [self setNeedsConfiguration];
 }
 
 // MARK: - Layout
 
 - (void) layoutSubviews {
-    if (self.hasConfigurationChanged) {
+    NSLog(@"%s", __func__);
+    
+    /*if (self.hasConfigurationChanged) {
         [self configureIndicator];
         self.configurationChanged = NO;
-    }
+    }*/
     
-    NSLog(@"Re-layout lines");
     for (CALayer *line in self.lines) {
         line.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
     }
 // MARK: - Animations
 
 - (void) addAnimations {
-    NSLog(@"%s", __func__);
-    NSLog(@"Line count: %d", [self.lines count]);
-    
     CGFloat duration = self.speed;
     NSInteger i =0;
     for (CALayer *line in lines) {
         CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"opacity"];
         anim.duration = duration;
         anim.repeatCount = HUGE_VALF;
-        anim.beginTime = duration - (duration / self.numberOfLines * i);
+        anim.beginTime = /* duration - */ (duration / self.numberOfLines * i);
         anim.fromValue = [NSNumber numberWithFloat:1.0];
         anim.toValue = [NSNumber numberWithFloat:kDimmedOpacity];
         
 
 // MARK: - Public API
 
+- (void) setStyle:(UIActivityIndicatorViewStyle)indicatorStyle {
+    
+}
+
 - (void) startAnimating {
     isAnimating = YES;
     [self addAnimations];
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.