今天做了一個(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)行下載。