iOS - 用 UIBezierPath 實現果凍效果

來源:互聯網
上載者:User

標籤:

最近在網上看到一個很酷的下拉重新整理效果(http://iostuts.io/2015/10/17/elastic-bounce-using-uibezierpath-and-pan-gesture/)。自己試著實現了一下其中的果凍回彈效果。

效果

DEMO
  • 由於文筆不太好-.- ,建議先下載demo,再結合下面的分析,會好理解點。地址https://github.com/Resory/RYCuteView

邏輯
  • p1,藍色部分圖形是一個CAShapeLayer,他的形狀由UIBezierPath的路徑組成的。

  • 這個路徑是由r1,r2,r3,r4,r5這5個紅點確定的。其中r1,r2,r3,r4都是不動點,唯一可以動的是r5點

  • 根據上面的動態圖可以看出,CAShapeLayer的形狀是隨著r5紅點的移動而相應變化的,所以只要獲得r5的座標變化就可以用UIBezierPath做出相應的路徑,然後就可以形成相應的形狀。

實現
  • 初始化CAShapeLayer
123456 - (void)configShapeLayer    _shapeLayer = [CAShapeLayer layer];    _shapeLayer.fillColor = [UIColor colorWithRed:57/255.0 green:67/255.0 blue:89/255.0 alpha:1.0].CGColor;    [self.layer addSublayer:_shapeLayer];}
  • 初始化r5點
123456789 - (void)configCurveView{    // _curveView就是r5點    _curveX = SYS_DEVICE_WIDTH/2.0;       // r5點x座標    _curveY = MIN_HEIGHT;                 // r5點y座標    _curveView = [[UIView alloc] initWithFrame:CGRectMake(_curveX, _curveY, 3, 3)];    _curveView.backgroundColor = [UIColor redColor];    [self addSubview:_curveView];}
  • 添加移動手勢&CADisplayLink
12345678910111213141516 - (void)configAction{    _mHeight = 100;                       // 手勢移動時相對高度    _isAnimating = NO;                    // 是否處於動效狀態     // 手勢    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanAction:)];    self.userInteractionEnabled = YES;    [self addGestureRecognizer:pan];     // calculatePath方法是算出在運行期間_curveView的座標,從而確定_shapeLayer的形狀    _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(calculatePath)];    [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];    // 在手勢結束的時候才調用calculatePath方法,所以一開始是暫停    _displayLink.paused = YES;    }
  • 手勢解析
    • 手勢移動時,r5紅點跟著手勢移動,_shapeLayer則根據r5的座標來擴大自己的地區

    • 手勢結束時,r5紅點通過UIView的動畫方法來改變r5的座標,同時_shapeLayer根據r5的座標縮小自己的地區並最終返回原形。

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253 - (void)handlePanAction:(UIPanGestureRecognizer *)pan{    if(!_isAnimating)    {        if(pan.state == UIGestureRecognizerStateChanged)        {            // 手勢移動時,_shapeLayer跟著手勢向下擴大地區            CGPoint point = [pan translationInView:self];             // 這部分代碼使r5紅點跟著手勢走            _mHeight = point.y*0.7 + MIN_HEIGHT;            _curveX = SYS_DEVICE_WIDTH/2.0 + point.x;            _curveY = _mHeight > MIN_HEIGHT ? _mHeight : MIN_HEIGHT;            _curveView.frame = CGRectMake(_curveX,                                          _curveY,                                          _curveView.frame.size.width,                                          _curveView.frame.size.height);             // 根據r5座標,更新_shapeLayer形狀            [self updateShapeLayerPath];         }        else if (pan.state == UIGestureRecognizerStateCancelled ||                 pan.state == UIGestureRecognizerStateEnded ||                 pan.state == UIGestureRecognizerStateFailed)        {            // 手勢結束時,_shapeLayer返回原狀併產生彈簧動效            _isAnimating = YES;            _displayLink.paused = NO;           //開啟displaylink,會執行方法calculatePath.             // 彈簧動效            [UIView animateWithDuration:1.0                                  delay:0.0                 usingSpringWithDamping:0.5                  initialSpringVelocity:0                                options:UIViewAnimationOptionCurveEaseInOut                             animations:^{                 // 曲線點(r5點)是一個view.所以在block中有彈簧效果.然後根據他的動效路徑,在calculatePath中計算彈性圖形的形狀                _curveView.frame = CGRectMake(SYS_DEVICE_WIDTH/2.0, MIN_HEIGHT, 3, 3);             } completion:^(BOOL finished) {                 if(finished)                {                    _displayLink.paused = YES;                    _isAnimating = NO;                }             }];        }    }}
  • 根據r5的位置,更新_shapeLayer形狀
123456789101112 - (void)updateShapeLayerPath{    // 更新_shapeLayer形狀    UIBezierPath *tPath = [UIBezierPath bezierPath];    [tPath moveToPoint:CGPointMake(0, 0)];  //r1點    [tPath addLineToPoint:CGPointMake(SYS_DEVICE_WIDTH, 0)];// r2點    [tPath addLineToPoint:CGPointMake(SYS_DEVICE_WIDTH,  MIN_HEIGHT)]; //r4點    [tPath addQuadCurveToPoint:CGPointMake(0, MIN_HEIGHT)                  controlPoint:CGPointMake(_curveX, _curveY)]; // r3,r4,r5確定的一個弧線    [tPath closePath];    _shapeLayer.path = tPath.CGPath;}
  • 計算彈簧效果座標
12345678 - (void)calculatePath{    // 由於手勢結束時,r5執行了一個UIView的彈簧動畫,把這個過程的座標記錄下來,並相應的畫出_shapeLayer形狀    CALayer *layer = _curveView.layer.presentationLayer;    _curveX = layer.position.x;    _curveY = layer.position.y;    [self updateShapeLayerPath];}
  • r5點的作用非常重要,因為直接對CAShapeLayer實現動效不太好實現。所以通過對r5點實現彈簧動效,記錄r5點的座標,再用UIBezierPath形成路徑,最後賦予CAShapeLayer,間接的完成了CAShapeLayer的彈簧動效。

連結:

iOS - 用 UIBezierPath 實現果凍效果

Elastic view animation using UIBezierPath

iOS - 用 UIBezierPath 實現果凍效果

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.