Skip to content

Instantly share code, notes, and snippets.

@DreamingInBinary
Created August 14, 2018 20:10
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DreamingInBinary/a4a2d5183b8b9a093ef9f682028653c9 to your computer and use it in GitHub Desktop.
Save DreamingInBinary/a4a2d5183b8b9a093ef9f682028653c9 to your computer and use it in GitHub Desktop.
UIView+BFRShimmering.m
//
// 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