美文网首页iOS开发攻城狮的集散地
iOS-OC仿Boss直聘下拉刷新动画

iOS-OC仿Boss直聘下拉刷新动画

作者: Hedgehog___ | 来源:发表于2018-06-20 17:50 被阅读348次
      在刷即刻的时候,突然发现它的首页刷新动画还不错,因此我就仿写了下boss直聘App的下拉刷新动画(别问为啥),在这里记录下来供大家参考讨论。最终运行效果如下: QQ20180620-162220-HD.gif

      废话不多说开始上代码了。首先创建一个CYXRefreshHeader

    @interface CYXRefreshHeader : UIView
    /*刷新block*/
    @property (nonatomic,strong) void(^refresh)(void);
    /*开始刷新*/
    -(void)startRefresh;
    /*结束刷新*/
    -(void)endRefresh;
    @end
    
    

    初始化三个点的Layer

    -(instancetype)init{
        if (self = [super init]) {
            self.backgroundColor = [UIColor whiteColor];
            self.frame = CGRectMake(0, HeaderHeight, HeaderWidth, HeaderHeight);
            [self.layer addSublayer:self.firstPointLayer];
            [self.layer addSublayer:self.secondPointLayer];
            [self.layer addSublayer:self.thirdPointLayer];
            self.firstPointLayer.frame = CGRectMake(HeaderWidth/2-RefreshArcRadius, HeaderHeight/2-RefreshArcRadius, RefreshArcRadius*2, RefreshArcRadius*2);
            self.secondPointLayer.frame = CGRectMake(HeaderWidth/2-RefreshArcRadius, HeaderHeight/2-RefreshArcRadius, RefreshArcRadius*2, RefreshArcRadius*2);
            self.thirdPointLayer.frame = CGRectMake(HeaderWidth/2-RefreshArcRadius, HeaderHeight/2-RefreshArcRadius, RefreshArcRadius*2, RefreshArcRadius*2);
            self.firstPointLayer.path = [self pointPath].CGPath;
            self.secondPointLayer.path = [self pointPath].CGPath;
            self.thirdPointLayer.path = [self pointPath].CGPath;
        }
        return self;
    }
    #pragma mark ---Path
    -(UIBezierPath *)pointPath{
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(RefreshArcRadius, RefreshArcRadius) radius:RefreshArcRadius startAngle:0 endAngle:M_PI * 2 clockwise:YES];
        return path;
    }
    

    在父视图改变的时候设置监听scrollview的滑动偏移量

    /*父视图改变的时候*/
    - (void)willMoveToSuperview:(UIView *)newSuperview {
        [super willMoveToSuperview:newSuperview];
        if ([newSuperview isKindOfClass:[UIScrollView class]]) {
            self.scrollView = (UIScrollView *)newSuperview;
            self.centerX = self.scrollView.width/2;
            self.bottom = 0;
            [self.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
        }else {
            [self.superview removeObserver:self forKeyPath:@"contentOffset"];
        }
    }
    

      这里- (void)willMoveToSuperview:(UIView *)newSuperview 方法的调用时机:
      当自己重写一个UIView的时候有可能用到这个方法,当本视图的父类视图改变的时候,系统会自动的执行这个方法.newSuperview是本视图的新父类视图.newSuperview有可能是nil.
      在监听偏移量的方法里实现随着偏移量三个点的变化:

    #pragma mark ---Kvo
    /*监听偏移量*/
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
        if ([keyPath isEqualToString:@"contentOffset"]) {
            self.offSet =  self.scrollView.contentOffset.y;
            [self setOffSetUI];
        }
    }
    /*设置*/
    -(void)setOffSetUI{
        //如果到达临界点,则执行刷新动画
        if (!self.isAnimating&&self.offSet<=0) {
            CGFloat scale = -self.offSet/RefreshFullOffset;
            if (scale>1) {scale=1;}
            if (scale<0) {scale=0;}
            CGFloat centerX = HeaderWidth/2;
            CGFloat maxLeftX = centerX-RefreshMaxWidth;
            CGFloat maxLeftDistance = centerX - maxLeftX;
            CGFloat maxRightX = centerX+RefreshMaxWidth;
            CGFloat maxRightDistance = maxRightX - centerX;
            
            self.firstPointLayer.frame = CGRectMake(centerX-maxLeftDistance*scale-RefreshArcRadius, HeaderHeight/2-RefreshArcRadius, RefreshArcRadius*2, RefreshArcRadius*2);
            self.thirdPointLayer.frame = CGRectMake(centerX+maxRightDistance*scale-RefreshArcRadius, HeaderHeight/2-RefreshArcRadius, RefreshArcRadius*2, RefreshArcRadius*2);
            CGFloat topY =-(RefreshFullOffset/2-RefreshFullOffset/2.0*(1.0-scale))-RefreshArcRadius*2;//y坐标的变化
            self.top = topY;
        }
        if (-self.offSet >= RefreshFullOffset && !self.isAnimating && !self.scrollView.dragging) {
            //刷新
            [self startAnimation];
            if (self.refresh) {
                self.refresh();
            }
        }
    }
    

    再达到临界值的时候执行刷新动作并执行刷新动画:

    /*执行动画*/
    -(void)startAnimation{
        self.isAnimating = YES;
        [UIView animateWithDuration:0.5 animations:^{
            UIEdgeInsets inset = self.scrollView.contentInset;
            inset.top = RefreshFullOffset;
            self.scrollView.contentInset = inset;
        }];
        CAKeyframeAnimation * animation = [self opacityAnimation];
        [self.firstPointLayer addAnimation:animation forKey:@"opacity"];
        
        animation = [self opacityAnimation];
        animation.beginTime = CACurrentMediaTime()+KeyAnimationDuration/2;
        [self.secondPointLayer addAnimation:animation forKey:@"opacity"];
        
        animation = [self opacityAnimation];
        animation.beginTime = CACurrentMediaTime()+KeyAnimationDuration;
        [self.thirdPointLayer addAnimation:animation forKey:@"opacity"];
    }
    -(CAKeyframeAnimation *)opacityAnimation{
        CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
        animation.duration = KeyAnimationDuration;
        
        animation.repeatCount = HUGE_VALF;
        animation.fillMode = kCAFillModeForwards;
        animation.duration = KeyAnimationDuration*2;
        animation.values = @[[NSNumber numberWithFloat:1.0f],
                             [NSNumber numberWithFloat:0.0f],
                             [NSNumber numberWithFloat:1.0f],
                             [NSNumber numberWithFloat:1.0f]];
        return animation;
    }
    

    最后再实现结束刷新的方法即可:

     -(void)endRefresh{
       [UIView animateWithDuration:0.5 animations:^{
            UIEdgeInsets inset = self.scrollView.contentInset;
            inset.top = 0.f;
            self.scrollView.contentInset = inset;
       } completion:^(BOOL finished) {
            [self stopAnimation];
            [self initLayerFrame];
       }];
    }
    
    /*初始化layer坐标*/
    -(void)initLayerFrame{
        self.firstPointLayer.frame = CGRectMake(HeaderWidth/2-RefreshArcRadius, HeaderHeight/2-RefreshArcRadius, RefreshArcRadius*2, RefreshArcRadius*2);
        self.secondPointLayer.frame = CGRectMake(HeaderWidth/2-RefreshArcRadius, HeaderHeight/2-RefreshArcRadius, RefreshArcRadius*2, RefreshArcRadius*2);
        self.thirdPointLayer.frame = CGRectMake(HeaderWidth/2-RefreshArcRadius, HeaderHeight/2-RefreshArcRadius, RefreshArcRadius*2, RefreshArcRadius*2);
    }
    /*停止动画*/
    -(void)stopAnimation{
        [UIView animateWithDuration:0.5 animations:^{
            UIEdgeInsets inset = self.scrollView.contentInset;
            inset.top = 0.f;
            self.scrollView.contentInset = inset;
        } completion:^(BOOL finished) {
            [self.thirdPointLayer removeAllAnimations];
            [self.firstPointLayer removeAllAnimations];
            [self.secondPointLayer removeAllAnimations];
            self.isAnimating = NO;
        }];
    }
    

    本文借鉴:https://www.jianshu.com/p/3c51e4896632
    demo:https://github.com/SionChen/CYXBossRefreshDemo/tree/master 欢迎讨论

    相关文章

      网友评论

        本文标题:iOS-OC仿Boss直聘下拉刷新动画

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