Created
August 14, 2018 20:10
-
-
Save DreamingInBinary/a4a2d5183b8b9a093ef9f682028653c9 to your computer and use it in GitHub Desktop.
UIView+BFRShimmering.m
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// UIView+BFRShimmer.h | |
// BFRUtils | |
// | |
// Created by Jordan Morgan on 8/14/18. | |
// Copyright © 2018 Buffer. All rights reserved. | |
// | |
#import <UIKit/UIKit.h> | |
NS_ASSUME_NONNULL_BEGIN | |
@interface UIView (BFRShimmer) | |
@property (strong, nonatomic, readonly, nonnull) CAGradientLayer *gradient; | |
@property (strong, nonatomic, readonly, nonnull) CABasicAnimation *shimmerAnimation; | |
- (void)startShimmering; | |
- (void)startShimmeringWithRepitions:(NSInteger)reps; | |
- (void)endShimmering; | |
@end | |
NS_ASSUME_NONNULL_END | |
// | |
// UIView+BFRShimmer.m | |
// BFRUtils | |
// | |
// Created by Jordan Morgan on 8/14/18. | |
// Copyright © 2018 Buffer. All rights reserved. | |
// | |
#import "UIView+BFRShimmer.h" | |
#import <objc/runtime.h> | |
static NSString * const BFR_SHIMMER_KEY = @"bfr.Shimmering.animationKey"; | |
@implementation UIView (BFRShimmer) | |
#pragma mark - Dynamic Properties | |
static const void *GradientKey = &GradientKey; | |
static const void *AnimationKey = &AnimationKey; | |
- (CAGradientLayer *)gradient { | |
CAGradientLayer *returnVal = objc_getAssociatedObject(self, GradientKey); | |
if (!returnVal) { | |
returnVal = [CAGradientLayer new]; | |
objc_setAssociatedObject(self, GradientKey, returnVal, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
} | |
return returnVal; | |
} | |
- (CABasicAnimation *)shimmerAnimation { | |
CABasicAnimation *returnVal = objc_getAssociatedObject(self, AnimationKey); | |
if (!returnVal) { | |
returnVal = [CABasicAnimation animationWithKeyPath:@"position"]; | |
objc_setAssociatedObject(self, AnimationKey, returnVal, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
} | |
return returnVal; | |
} | |
#pragma mark - Public API | |
- (void)startShimmeringWithRepitions:(NSInteger)reps { | |
[CATransaction begin]; | |
[CATransaction setCompletionBlock:^{ | |
[self endShimmering]; | |
}]; | |
UIColor *lightColor = [[UIColor whiteColor] colorWithAlphaComponent:0.1]; | |
UIColor *darkColor = [[UIColor blackColor] colorWithAlphaComponent:1.0]; | |
CGFloat length = CGRectGetWidth(self.layer.bounds); | |
CGFloat extraDistance = length + 1.0f * 0.4f; | |
CGFloat fullShimmerLength = length * 3.0f + extraDistance; | |
CGFloat travelDistance = length * 2.0f + extraDistance; | |
CGFloat highlightOutsideLength = 0.0 / 2.0; | |
CGFloat startPoint = (length + extraDistance) / fullShimmerLength; | |
CGFloat endPoint = travelDistance / fullShimmerLength; | |
self.gradient.bounds = CGRectMake(0.0, 0.0, fullShimmerLength, CGRectGetHeight(self.layer.bounds)); | |
self.gradient.position = CGPointMake(-travelDistance, 0.0); | |
self.gradient.anchorPoint = CGPointZero; | |
self.gradient.startPoint = CGPointMake(startPoint, 0.0); | |
self.gradient.endPoint = CGPointMake(endPoint, 0.0); | |
self.gradient.locations = @[@(highlightOutsideLength), @(0.5), @(1.0 - highlightOutsideLength)]; | |
self.gradient.colors = @[(id)darkColor.CGColor, (id)lightColor.CGColor, (id)darkColor.CGColor]; | |
self.shimmerAnimation.duration = 1.0; | |
self.shimmerAnimation.repeatCount = reps > 0 ? reps : INFINITY; | |
self.shimmerAnimation.toValue = [NSValue valueWithCGPoint:CGPointZero]; | |
[self.gradient addAnimation:self.shimmerAnimation forKey:BFR_SHIMMER_KEY]; | |
self.layer.mask = self.gradient; | |
[CATransaction commit]; | |
} | |
- (void)startShimmering { | |
[self startShimmeringWithRepitions:0]; | |
} | |
- (void)endShimmering { | |
[self.layer.mask removeAnimationForKey:BFR_SHIMMER_KEY]; | |
self.layer.mask = nil; | |
[self.layer setNeedsDisplay]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment