實現一個iOS漸變背景動畫效果的Switch
前言
在dribbble看到一個Switch動畫效果就手癢想實現,下面就是我實現的思路。
源代碼
GitHub地址: VGGradientSwitch
如果覺得不錯,歡迎點star。
設計圖
來自dribbble上的設計作者 Nick Buturishvili
image
效果圖
image
思路
- 首先解刨一下設計圖
- 外觀和iOS原生UISwitch相同
- 觀察動圖發現Switch背景圖為漸變色,這也是這個開關設計的一大亮點
- 開關上的紐扣,打開時狀態是一個勾,關閉時是一個叉。
- 打開動畫,勾邊線放大移動邊做形變變成點再變換成叉放大后恢復原狀,背景顏色由青色轉換到橘黃色。
- 關閉動畫,叉邊先放大移動邊做形變再變成勾放大后恢復原狀,背景顏色由橘黃色轉換到青色
實現
-
漸變背景圖是通過 CAGradientLayer 實現。通過設計圖取色拿到顏色十六進制(0x08ded6,0x18deb9,0xef9c29,0xe76b39)四個顏色,創建出一個switch3倍寬的漸變圖
如圖:
gradientBackground.png
代碼如下:
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.locations = @[@0, @.33, @.63, @1];
gradientLayer.startPoint = CGPointMake(0, 0);
gradientLayer.endPoint = CGPointMake(1, 0);
gradientLayer.frame = CGRectMake(0, 0, self.frame.size.width * 3, self.frame.size.height);
- 邊框使用 UIBezierPath 設置一個圓角邊框
border.png
- 勾、點和叉的實現使用到 UIBezierPath 提供path,然后 CAShapeLayer 創建,勾圖形實現代碼如下:
UIBezierPath tickPath = [UIBezierPath bezierPath];
[tickPath moveToPoint:CGPointMake(self.frame.size.width/8 3, self.frame.size.width/2)];
CGPoint p1 = CGPointMake(self.frame.size.width/2, self.frame.size.width/8 5);
[tickPath addLineToPoint:p1];
CGPoint p2 = CGPointMake(self.frame.size.width/8 6, self.frame.size.width/8 * 3);
[tickPath addLineToPoint:p2];
CAShapeLayer layer = [[CAShapeLayer alloc] init];
layer.lineCap = kCALineCapRound;
layer.lineJoin = kCALineJoinRound;
layer.fillColor = [UIColor clearColor].CGColor;
layer.strokeColor = [UIColor whiteColor].CGColor;
layer.lineWidth = 2;
layer.path = tickPath.CGPath;</code></pre>

tick.png
- 漸變背景顏色的動畫效果,筆者是將 CAGradientLayer 添加到一個UIView上然后直接使用,UIView的動畫方法然后做位移,代碼如下:
[UIView animateKeyframesWithDuration:.5 delay:.1 options:UIViewKeyframeAnimationOptionCalculationModePaced animations:^{
self.gradientView.frame = CGRectMake(-self.frame.size.width
2, 0, self.frame.size.width *3, self.frame.size.height);
} completion:^(BOOL finished) {
}];</code></pre>

gradient_animation.gif
- 圖形形變動畫主要利用 Core Animation 實現,用到了 CAKeyframeAnimation 、 CABasicAnimation 、 CAAnimationGroup
- 勾->點動畫 先放大勾后然后做縮小形變成點
- 點->勾動畫 做形變成勾后做放大
-
動畫使用了"path"和"transform",形變動畫使用path提供路徑數組,這里提供原本勾的路徑和點的路徑這樣路徑就從勾形變到點
代碼如下:
-
放大動畫 使用 CABasicAnimation
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
CATransform3D tr = CATransform3DIdentity;
tr = CATransform3DTranslate(tr, _rect.size.width/2, _rect.size.height/2, 0);
tr = CATransform3DScale(tr, 1.2, 1.2, 1);
tr = CATransform3DTranslate(tr, -_rect.size.width/2, -_rect.size.height/2, 0);
animation.toValue = [NSValue valueWithCATransform3D:tr];
animation.autoreverses = YES;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
- 形變動畫 使用 CAKeyframeAnimation 具體的使用可以Google一下這里就不多贅言, values 傳入的是勾的path和點path
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"path"];
animation.values = values;
animation.keyTimes = keyTimes;
animation.beginTime = beginTime;
- 使用 CAAnimationGroup 做組合動畫,組合動畫代理方法可以判斷組合動畫是否完成, <CAAnimationDelegate> 代碼如下:
// scaleAnimation 放大 lineAnimation線條形變
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = @[scaleAnimation,lineAnimation];
animationGroup.duration = .5;
animationGroup.repeatCount = 1;
animationGroup.removedOnCompletion = NO;
animationGroup.fillMode = kCAFillModeForwards;
animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animationGroup.delegate = self;
// CAAnimationDelegate 動畫是否結束
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
}

1.gif
- 剩下的就是移動這個按鈕然后由點形變成叉,這里就不再說明,可以直接看GitHub代碼,以上就是分解動畫的一些思路和解決辦法,但是動畫要流暢和交互不違和還需要細微調整
- 有什么代碼和實現的效果建議可以提issue給我,如果喜歡的話點一下 star 哦
來自:http://www.jianshu.com/p/2cbbf220ef07