页面边缘回弹效果

作者: LeesinS | 来源:发表于2016-09-22 17:19 被阅读444次

    实现页面边缘的滑动回弹效果,封装成可以自定义颜色以及回弹的边缘位置,

    效果图.gif

    注释还算详细,就不赘述了,关键有两点
    一: 根据手势获取画贝塞尔曲线的控制点的坐标
    二: CADisplayLink计时器的控制

    代码如下
    BezierView.h

    #import <UIKit/UIKit.h>
    @interface BezierView : UIView
    /**
     创建BezierView实例
     实现下面的方法
     frame决定贝塞尔曲线控制点的位置, color决定图层的颜色
     */
    - (void)initShapeLayer:(CGRect)frame with:(UIColor*)color;
    @end
    

    BezierView.m

    #import "BezierView.h"
    
    #define WIDTH [UIScreen mainScreen].bounds.size.width
    #define HEIGHT [UIScreen mainScreen].bounds.size.height
    
    @interface BezierView()
    @property (nonatomic, strong) UIView *controlPoint;// 绘制贝塞尔曲线的控制点
    @property (nonatomic, assign) CGFloat pointX; //点的X坐标,滑动时会改变
    @property (nonatomic, assign) CGFloat pointY; //点的Y坐标,滑动时会改变
    @property (nonatomic, strong) CAShapeLayer *pointShapeLayer; //滑动时出现的曲面
    @property (nonatomic, assign) BOOL isAnimating;//根据动画状态来自动回弹 初始为NO
    @property (nonatomic, strong) CADisplayLink *disPlayLink;//计时器
    @property (nonatomic, assign)  CGRect pframe;//point的frame
    @end
    
    
    @implementation BezierView
    
    - (instancetype)initWithFrame:(CGRect)frame{
        self = [super initWithFrame:frame];
        if (self) {
            self.alpha = 0.2;//view的透明度 决定 shapeLayer的透明度
            [self addGesture];
            
        }
        return self;
    }
    
    - (void)addGesture{
        
        _isAnimating = NO; //是否处于动画状态
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
        
        self.userInteractionEnabled = YES;
        [self addGestureRecognizer:pan];
        
        // 创建计时器
        _disPlayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(getPath)];
        [_disPlayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        _disPlayLink.paused = YES;
        
    }
    
    
    #pragma 初始化shapeLayer和曲线控制点
    - (void)initShapeLayer:(CGRect)frame with:(UIColor *)color{
        self.pframe = frame;
        _pointShapeLayer = [CAShapeLayer layer];
        _pointShapeLayer.fillColor = color.CGColor;
        [self.layer addSublayer:_pointShapeLayer];
        _controlPoint = [[UIView alloc] initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, 10, 10)];
        _controlPoint.backgroundColor = [UIColor blackColor];
        [self addSubview:_controlPoint];
     
    }
    #pragma 滑动时改变贝塞尔曲线控制点的frame
    
    - (void)panAction:(UIPanGestureRecognizer *)pan{
        
        
        if (!_isAnimating) {
            if (pan.state == UIGestureRecognizerStateChanged) {
                CGPoint point = [pan translationInView:self];
                //point跟着手势动
                
                _pointX = self.pframe.origin.x + point.x;//此处加上系数 可以 决定边缘动画的最大范围 X,Y可选择性控制
                _pointY = self.pframe.origin.y + point.y;
                _controlPoint.frame = CGRectMake(_pointX, _pointY, _controlPoint.frame.size.width, _controlPoint.frame.size.height);
    
                //当point改变 各自的shaplayer也跟着变
                [self updateShapeLayerPath];
            }else if (pan.state == UIGestureRecognizerStateCancelled ||
                      pan.state == UIGestureRecognizerStateEnded ||
                      pan.state  == UIGestureRecognizerStateFailed){
                
                _isAnimating = YES;
                
                //displaylink处于开启状态,会执行方法getPath. 此时应当关闭
                _disPlayLink.paused = NO;
                
                // shaplayer根据点画出来的  所以point回弹 shaplayer也会回弹
                [UIView animateWithDuration:1.0
                                      delay:0.0
                     usingSpringWithDamping:1.0
                      initialSpringVelocity:0
                                    options:UIViewAnimationOptionCurveEaseInOut
                                 animations:^{
                                     _controlPoint.frame = CGRectMake(self.pframe.origin.x,  self.pframe.origin.y, 10, 10);
                                    
                                 } completion:^(BOOL finished) {
                                     if(finished)
                                     {
                                         _disPlayLink.paused = YES;
                                         _isAnimating = NO;
                                     }
                                 }];
            }
        }
        
    }
    
    - (void)updateShapeLayerPath{
        
        // 更新_shapeLayer形状,贝塞尔曲线其实就是根据一条直线和一个点描绘出一条曲线,以向右滑动为例,首先确定一条直线,这条直线就是从(0,0)到(0,HEIGHT)这个线,然后就可以根据controlPoint去描绘这条曲线了
        //根据controlPoint的坐标画出shaplayer的形状
        UIBezierPath *pointPath = [UIBezierPath bezierPath];
        
        if (self.pframe.origin.y == 0 || self.pframe.origin.y == HEIGHT) {
            [pointPath moveToPoint:CGPointMake(0, self.pframe.origin.y)];
            [pointPath addLineToPoint:CGPointMake(WIDTH, self.pframe.origin.y)];
            [pointPath addQuadCurveToPoint:CGPointMake(0, self.pframe.origin.y) controlPoint:CGPointMake(_pointX, _pointY)];
            [pointPath closePath];
    
        }else if (self.pframe.origin.x == 0 || self.pframe.origin.x == WIDTH){
            [pointPath moveToPoint:CGPointMake(self.pframe.origin.x, 0)];
            [pointPath addLineToPoint:CGPointMake(self.pframe.origin.x, HEIGHT)];
            [pointPath addQuadCurveToPoint:CGPointMake(self.pframe.origin.x, 0) controlPoint:CGPointMake(_pointX, _pointY)];
            [pointPath closePath];
        }
        _pointShapeLayer.path = pointPath.CGPath;
    
    }
    
    - (void)getPath{
        
       // 记录controlPoint回弹时的坐标
        CALayer *layer = _controlPoint.layer.presentationLayer;
        _pointX = layer.position.x;
        _pointY = layer.position.y;
        [self updateShapeLayerPath];
        
    }
    
    
    
    @end
    

    使用的时候只用创建BeaierView这个实例并实现其.h中的方法就可以了
    例:

        BezierView *beView = [[BezierView alloc] initWithFrame:CGRectMake(0, 0,  WIDTH, HEIGHT)];
        beView.backgroundColor = [UIColor grayColor];
        
        
        [beView initShapeLayer:CGRectMake(0  ,HEIGHT / 2,10, 10) with:[UIColor redColor]];
    
    

    相关文章

      网友评论

      • 韦弦Zhy:手机版简书怎么看完整代码………
        LeesinS: @韦弦Zhy 代码框下面有一个滚动条,滚动的时候才看得见,
      • 伊泽冠铭:好厉害哟,我要跟你生猴子🐒
        伊泽冠铭:@LeesinS 你个骚猪🐖
        LeesinS:@伊泽冠铭 来吧 小贱人

      本文标题:页面边缘回弹效果

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