美文网首页
iOS之Shimmer源码解析

iOS之Shimmer源码解析

作者: 人仙儿a | 来源:发表于2017-12-05 21:34 被阅读34次
    shimmer.gif | center

    前言

    Shimmerfacebook的开源动画库,可以实现闪现文字的效果,在paperapp里用到了,虽然paper没有火起来,但是这个效果还是很不错的。它的源码只有几百行,很容易学习理解。
    源码的github地址在这

    1.通过宏来创建属性的getter和setter方法:

    #define LAYER_ACCESSOR(accessor, ctype) \
    - (ctype)accessor { \
      return [__layer accessor]; \
    }
    ![Alt text](./shimmer.gif)
    
    #define LAYER_MUTATOR(mutator, ctype) \
    - (void)mutator (ctype)value { \
      [__layer mutator value]; \
    }
    
    #define LAYER_RW_PROPERTY(accessor, mutator, ctype) \
      LAYER_ACCESSOR (accessor, ctype) \
      LAYER_MUTATOR (mutator, ctype)
    
    LAYER_RW_PROPERTY(isShimmering, setShimmering:, BOOL)
    LAYER_RW_PROPERTY(shimmeringPauseDuration, setShimmeringPauseDuration:, CFTimeInterval)
    LAYER_RW_PROPERTY(shimmeringAnimationOpacity, setShimmeringAnimationOpacity:, CGFloat)
    LAYER_RW_PROPERTY(shimmeringOpacity, setShimmeringOpacity:, CGFloat)
    LAYER_RW_PROPERTY(shimmeringSpeed, setShimmeringSpeed:, CGFloat)
    LAYER_RW_PROPERTY(shimmeringHighlightLength, setShimmeringHighlightLength:, CGFloat)
    LAYER_RW_PROPERTY(shimmeringDirection, setShimmeringDirection:, FBShimmerDirection)
    LAYER_ACCESSOR(shimmeringFadeTime, CFTimeInterval)
    LAYER_RW_PROPERTY(shimmeringBeginFadeDuration, setShimmeringBeginFadeDuration:, CFTimeInterval)
    LAYER_RW_PROPERTY(shimmeringEndFadeDuration, setShimmeringEndFadeDuration:, CFTimeInterval)
    LAYER_RW_PROPERTY(shimmeringBeginTime, setShimmeringBeginTime:, CFTimeInterval)
    

    用宏的方式来实现多个方法,节省代码量。如果你经常看第三方源码的话,会发现这种方式也很常见的。
    2.打个差,因为后面会讲到蒙板,先介绍一下mask
    这是我写的一个demo:

    CALayer *layer1 = [[CALayer alloc] init];
        layer1.frame = CGRectMake(50, 100, 120, 120);
        layer1.backgroundColor = [UIColor colorWithRed:1.0 green:0 blue:0 alpha:0.2].CGColor;
        
        CALayer *layer2 = [[CALayer alloc] init];
        layer2.frame = CGRectMake((120 - 60)/2, (120-60)/2, 60, 60);
        layer2.backgroundColor = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;
    
        layer1.mask = layer2;
    
        [self.view.layer addSublayer:layer1];
    
    mask

    测试结果可知:

    1. 蒙版mask的颜色值是不会起作用的,只以设置做任意颜色值,只有它的alpha起作用。
    2. 我们将layer的alpha是0.2, maskLayer是1.0,结果的alpha值是0.2。调一下个儿,将layer的alpha是1.0, maskLayer是0.2,结果的alpha值是0.2。可以看来两个alpha值的共同作用是最终的值. 所以得出公式:
      alpha = layer的alpha * maskLayer的alpha

    3.如何实现中间高亮的效果?
    看源码发现里面主要用到二个Layer,

    • _maskLayer:_contentLayer.mask = _maskLayer, 实现蒙层效果
    • _fadeLayer :是_maskLayer里的subLayer, 为了实现淡入淡出效果

    maskLayer定义:

    @interface FBShimmeringMaskLayer : CAGradientLayer
    @property (readonly, nonatomic) CALayer *fadeLayer;
    @end
    

    疑问1:maskLayer的bound是多少
    我本来以为maskLayer的bound大小是白色高度部分,但仔细一想不对,这样的话,非高亮的部分就会被隐藏!我看了一下源码maskLayer的bound大小,原来跟_contentLayer的大小一样,哦那就对了。

    疑问2:mask和contentLayer大小一样了,蒙层还有什么用?蒙层不就是为了扣图么?
    仔细看maskLayer是继承了CAGradientLayer,但是做颜色渐变有什么用呢,因为蒙层的颜色值是起不到作用的, 渐变效果也看不出来呀!我又蒙逼了!我们再仔细看源码:

    UIColor *maskedColor = [UIColor colorWithWhite:1.0 alpha:_shimmeringOpacity];//alpha: 1.0
      UIColor *unmaskedColor = [UIColor colorWithWhite:1.0 alpha:_shimmeringAnimationOpacity];//alpha: 0.5
    
      // Create a gradient from masked to unmasked to masked.
      _maskLayer.colors = @[(__bridge id)maskedColor.CGColor, (__bridge id)unmaskedColor.CGColor, (__bridge id)maskedColor.CGColor];
    

    它设了2个渐变颜色,这个颜色的alpha一个是1.0,另一个是0.5, 找到了真相!虽然颜色没什么用,但是alpha有用呀!所以渐变效果还是能展示的!所以最终最终的效果就是两边部分显示正常,中间部分显示高亮!

    淡入淡出效果

    static CABasicAnimation *fade_animation(CALayer *layer, CGFloat opacity, CFTimeInterval duration)
    {
      CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
      animation.fromValue = @([(layer.presentationLayer ?: layer) opacity]);
      animation.toValue = @(opacity);
      animation.fillMode = kCAFillModeBoth;
      animation.removedOnCompletion = NO;
      animation.duration = duration;
      FBShimmeringLayerAnimationApplyDragCoefficient(animation);
      return animation;
    }
    

    滑动效果

    static CABasicAnimation *shimmer_slide_animation(CFTimeInterval duration, FBShimmerDirection direction)
    {
      CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
      animation.toValue = [NSValue valueWithCGPoint:CGPointZero];
      animation.duration = duration;
      animation.repeatCount = HUGE_VALF;
      FBShimmeringLayerAnimationApplyDragCoefficient(animation);
      if (direction == FBShimmerDirectionLeft ||
          direction == FBShimmerDirectionUp) {
        animation.speed = -fabsf(animation.speed);
      }
      return animation;
    }
    

    通过动态改变maskLayer的position位置,实现maskLayer从左向右滑动的动态效果。其实苹果开锁的效果也是这样的,原理是相同的!


    ios_lock_text.gif | center

    相关文章

      网友评论

          本文标题:iOS之Shimmer源码解析

          本文链接:https://www.haomeiwen.com/subject/dprhixtx.html