飄動(dòng)心形的簡(jiǎn)單動(dòng)畫(huà)

今天做了一個(gè)點(diǎn)擊按鈕飄動(dòng)心形的簡(jiǎn)單動(dòng)畫(huà),效果如下:

gifAnimate.gif

每點(diǎn)擊一下按鈕,就生成一個(gè)心形,并執(zhí)行飄動(dòng)的動(dòng)畫(huà)。封裝heartView主要就兩件事:1.畫(huà)一個(gè)心形 2.執(zhí)行動(dòng)畫(huà)

  • 畫(huà)心形思路:左邊一個(gè)弧度-接著左邊一個(gè)半圓-接著右邊一個(gè)半圓-最后右邊一個(gè)弧度閉合,代碼如下:
//畫(huà)圖 需要在自帶的drawRect方法中操作
- (void)drawRect:(CGRect)rect
{
    //設(shè)置顏色
    [_strokeColor setStroke];
    [_fillColor setFill];
    
    CGFloat drawingPadding = 4.0;
    //??上面的圓的半徑 寬度減去兩邊空隙除以4
    CGFloat curveRadius = floor((CGRectGetWidth(rect) - 2*drawingPadding) / 4.0);
    
    //創(chuàng)建路徑
    UIBezierPath *heartPath = [UIBezierPath bezierPath];
    
    //以??的底部頂點(diǎn)為基點(diǎn) 順時(shí)針畫(huà):弧度-半圓-半圓-弧度連接基點(diǎn)
    
    //1.移動(dòng)到??的底部頂點(diǎn)
    CGPoint bottomLocation = CGPointMake(floor(CGRectGetWidth(rect) / 2.0), CGRectGetHeight(rect) - drawingPadding);
    [heartPath moveToPoint:bottomLocation];
    
    //2.畫(huà)左邊的弧形 貝賽爾曲線(xiàn)
    //endpoint x:4 y:高度一半以上一點(diǎn)
    CGPoint endPintLeftCurve = CGPointMake(drawingPadding, floor(CGRectGetHeight(rect) / 2.4));
    [heartPath addQuadCurveToPoint:endPintLeftCurve controlPoint:CGPointMake(endPintLeftCurve.x, endPintLeftCurve.y + curveRadius)];
    
    //3.畫(huà)左邊的半圓 startAngle:起始的弧度(PI3.14為180度 2PI為360度) endAngle:圓弧結(jié)束的弧度 clockwise:YES為順時(shí)針,No為逆時(shí)針
    [heartPath addArcWithCenter:CGPointMake(endPintLeftCurve.x + curveRadius, endPintLeftCurve.y) radius:curveRadius startAngle:PI endAngle:0 clockwise:YES];
    
    //4.畫(huà)右邊的半圓
    //計(jì)算右邊半圓的圓心
    CGPoint topRightCurveCenter = CGPointMake(endPintLeftCurve.x + 3*curveRadius, endPintLeftCurve.y);
    [heartPath addArcWithCenter:topRightCurveCenter radius:curveRadius startAngle:PI endAngle:0 clockwise:YES];
    
    //5.畫(huà)右邊的弧形 貝塞爾曲線(xiàn)
    CGPoint rightControlPoint = CGPointMake(endPintLeftCurve.x + 4*curveRadius, endPintLeftCurve.y + curveRadius);
    [heartPath addQuadCurveToPoint:bottomLocation controlPoint:rightControlPoint];
    
    
    [heartPath fill];
    heartPath.lineWidth = 1;
    heartPath.lineCapStyle = kCGLineCapRound;   //線(xiàn)條拐點(diǎn)
    heartPath.lineJoinStyle = kCGLineCapRound;  //終點(diǎn)處理
    [heartPath stroke];
}
  • 執(zhí)行動(dòng)畫(huà):
    通過(guò)提供一個(gè)公開(kāi)的- (void)animateInView:(UIView *)view;方法供外部調(diào)用。里面分別加了四個(gè)動(dòng)畫(huà)效果:1開(kāi)始的跳動(dòng)顯現(xiàn)2過(guò)程中旋轉(zhuǎn)3按照貝塞爾曲線(xiàn)移動(dòng)一段距離4結(jié)束動(dòng)畫(huà),此方法的實(shí)現(xiàn)如下:
- (void)animateInView:(UIView *)view
{
    NSTimeInterval totalAnimationDuration = 6;
    CGFloat heartWidth = CGRectGetWidth(self.bounds);
    CGFloat heartCenterX = self.center.x;
    CGFloat viewHeight = CGRectGetHeight(view.bounds);
    
    //初始化
    self.transform = CGAffineTransformMakeScale(0, 0);
    self.alpha = 0;
    
    //1.跳動(dòng)顯現(xiàn)出來(lái)
    [UIView animateWithDuration:0.5 delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.8 options:UIViewAnimationOptionCurveEaseOut animations:^{
        self.transform = CGAffineTransformIdentity;
        self.alpha = 0.9;
    } completion:NULL];
    
    //2.旋轉(zhuǎn)角度
    NSInteger i = arc4random_uniform(2);        //0 1 兩個(gè)值 不含上界
    NSInteger rotationDirection = 1 - (2*i);    // -1 OR 1
    NSInteger rotationFraction = arc4random_uniform(10);
    [UIView animateWithDuration:totalAnimationDuration animations:^{
        self.transform = CGAffineTransformMakeRotation(rotationDirection * PI/(6 + rotationFraction * 0.2));
    } completion:NULL];
    
    //3.按照貝賽爾曲線(xiàn)移動(dòng)幀動(dòng)畫(huà)
    UIBezierPath *heartTravelPath = [UIBezierPath bezierPath];
    [heartTravelPath moveToPoint:self.center];
    //生成結(jié)束點(diǎn) 在一定范圍內(nèi)隨機(jī) 和旋轉(zhuǎn)方向同一側(cè)
    CGPoint endPoint = CGPointMake(heartCenterX + rotationDirection * 2 * heartWidth, viewHeight / 6.0 + arc4random_uniform(viewHeight/4.0));   //以至少高度的六分之一為起點(diǎn)加上 0到四分之一高度之間的隨機(jī)數(shù)
    //生成控制點(diǎn) 也是在一定范圍內(nèi)隨機(jī)
    NSInteger j = arc4random_uniform(2);
    NSInteger travelDirection = 1 - (2 * i);
    CGFloat xDelta = (heartWidth/2.0 + arc4random_uniform(2*heartWidth)) * travelDirection * 2; //這個(gè)2可以控制寬度的倍數(shù)
    CGFloat yDelta = MAX(endPoint.y, MAX(arc4random_uniform(8*heartWidth), heartWidth));
    CGPoint controlP1 = CGPointMake(heartCenterX + xDelta, viewHeight - yDelta);
    CGPoint controlP2 = CGPointMake(heartCenterX - 2*xDelta, yDelta);
    [heartTravelPath addCurveToPoint:endPoint controlPoint1:controlP1 controlPoint2:controlP2];
    
    CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    keyFrameAnimation.path = heartTravelPath.CGPath;
    keyFrameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    keyFrameAnimation.duration = totalAnimationDuration + endPoint.y / viewHeight;
    
    [self.layer addAnimation:keyFrameAnimation forKey:@"positionOnPath"];
    
    //4.移除動(dòng)畫(huà)收尾 Alpha & remove from superview
    [UIView animateWithDuration:totalAnimationDuration animations:^{
        self.alpha = 0.0;
    } completion:^(BOOL finished) {
        [self removeFromSuperview];
    }];
}

很小的一個(gè)demo,積小流成江海。完整demo的github地址:心形飄動(dòng)demo請(qǐng)點(diǎn)擊此鏈接進(jìn)行下載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,242評(píng)論 25 708
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,229評(píng)論 4 61
  • 2016-01-30 13:30:48 一個(gè)讓你留在北京的理由 問(wèn)過(guò)很多剛畢業(yè)的年輕人,以后想在哪座城市發(fā)展,很多...
    霓為衣兮風(fēng)為馬閱讀 567評(píng)論 0 1
  • 經(jīng)過(guò)一段時(shí)間的胡思亂想、胡作非為之后,我決心胡說(shuō)八道一番,因?yàn)楸敬未髸?huì)實(shí)在是“后患無(wú)窮”,這一切都得益于洋蔥數(shù)學(xué)團(tuán)...
    小幸甫閱讀 3,098評(píng)論 2 10
  • 我的一輩子就是一張紙 某年某月某日 是我的生產(chǎn)日期 那孩提的哭啼 童年的歡聲笑語(yǔ) 少年時(shí)桀驁不馴的叛逆 愛(ài)情里患得...
    你咸我淡閱讀 220評(píng)論 0 1