先上效果圖:
圓形
方形
思路分析:
這四種風格其實就是兩種, 一種是動畫效果在視圖View的內部, 另一種是在視圖的外部! 我們可以嘗試封裝自訂 View 設定相關屬性去實現這兩個風格. 點擊時候觸及動畫, 說明要在這個 View 上添加手勢! 分析動畫效果其實是兩種, 第一種是視圖的比例由小到大,第二種是動畫顯示效果是漸漸層暗! 那麼我們可以把兩種效果寫到一個動畫組中!還有一個問題是效果的形狀, 也就是 Layer 動畫展示的形狀有方形有圓形, 這個形狀就需要我們思考如何去繪製和判斷!
程式碼分析:
首先要建立自訂一個 View 類去實現點擊有動畫的效果! 因為分析有兩種風格(在外在內)的動畫, 因此要在. h 檔案中聲明屬性去接收外界告知的風格! 我們還可以添加一些供外界修改的值, 比如動畫的邊界粗細, 填充顏色, 動畫時間等等這裡我用一個顏色舉例! 外界可提供一個顏色, 怎麼用具體代碼中有!
typedef NS_ENUM(NSUInteger, FlashButtonType){ # 風格定義一個枚舉類型的去表示 分別是代表動畫在裡面和外面 (便於理解) DDFlashButtonInner = 0, DDFlashButtonOuter = 1};# 定義的兩個屬性@property (strong, nonatomic) UIColor *flashColor;@property (assign, nonatomic) FlashButtonType buttonType;# 寫這個方法可以對 View 的子視圖上的子控制項進行操作, 可以不把子控制項都暴露出去- (void)setText:(NSString *)text withTextColor:(UIColor *)textColor;
第 2 步: 在初始化方法中,我們可以給這個 view 加一些子視圖比如 UILabel 去顯示一些想表達的文字(這裡還可以寫個方法去改變 label上 text 的屬性,)! 還需要給 View 添加點選手勢!
- (instancetype) initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) {# 建立手勢 並添加到 View 上 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap:)]; [self addGestureRecognizer:tap]; self.textLabel = [[UILabel alloc] initWithFrame:self.bounds]; self.textLabel.backgroundColor = [UIColor clearColor]; [self.textLabel setTextAlignment:NSTextAlignmentCenter]; [self addSubview:self.textLabel]; self.backgroundColor = [UIColor cyanColor];# 給一個預設的風格 不設定就是代表 動畫在裡面 self.buttonType = DDFlashButtonInner; } return self;}
第 3 步: 可以給子控制項給一些屬性 這裡有 label 還寫了個方法
- (void)setText:(NSString *)text withTextColor:(UIColor *)textColor{# 就是給 Label 賦外界傳來的值 若有其他的控制項可以改一些參數用此方法 if (text) { [self.textLabel setText:text]; } if (textColor) { [self.textLabel setTextColor:textColor]; }}
第 4 步: 根據風格的不同我們要控制動畫展示的範圍, 也就是加入動畫在內部就不能超過 View 的範圍
# 這裡就是重寫了ButtonType setter方法,同時判斷一下風格根據風格選擇是否把超過視圖 View 的部分裁剪掉- (void)setButtonType:(FlashButtonType)buttonType{ _buttonType = buttonType; if (buttonType == DDFlashButtonInner) {// 內容和子視圖是夾在視圖的邊界內 ( 只允許 view範圍內有子視圖和類容可以顯示 ) self.clipsToBounds = 1; }else {// 外面可以顯示 self.clipsToBounds = 0; }}
第 5 步: 準備工作做好後, 一個思路就是去寫點擊事件, 需要什麼就去建立什麼! 這先去思考點擊事件中需要的東西, 都滿足之後再去寫完善點擊事件! 動畫效果首先需要動畫, 另外還需要能添加動畫的 Layer;首先寫個得到動畫的方法!
- (CAAnimationGroup *)createFlashAnimationWisthScale:(CGFloat)scale duration:(CGFloat)duratiton{# 建立按比例收縮變大的動畫// 指定要在渲染動畫效能時的關鍵路徑 也就是圖形轉換的方式 這裡是按收縮比例 這裡也可以不用.scale 因為我們初始值設定是根據CATransform3D CABasicAnimation *scaleAnnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];// 動畫開始點 // 這個動畫效果初值 就是本身的原始的位置 scaleAnnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; // 等價 scaleAnnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)];// 動畫結束點 // 在 x 軸和 y 軸的變化比例 scaleAnnimation.toValue = [NSValue valueWithCATransform3D:(CATransform3DMakeScale(scale, scale, 1))];# 建立透明度變換的動畫 CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; alphaAnimation.fromValue = @1; alphaAnimation.toValue = @0;# 建立動畫組把上面兩個動畫加進去 CAAnimationGroup *animation = [CAAnimationGroup new]; animation.animations = @[scaleAnnimation,alphaAnimation];// 動畫效果 (節奏, Timing Function的會被用於變化起點和終點之間的插值計算.形象點說是Timing Function決定了動畫啟動並執行節奏(Pacing),比如是均勻變化(相同時間變化量相同),先快後慢,先慢後快還是先慢再快再慢.) animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];# 返回我們想要的動畫效果組 return animation;}
第 6 步: 得到一個CAShapeLayer 類型的圖層(因為要結合貝茲路徑得到形狀路徑), 畫一個形狀那麼就需要有位置
- (CAShapeLayer *)creatCircleShapWithPostion:(CGPoint)position pathRect:(CGRect)rect radius:(CGFloat)radius{ CAShapeLayer *circleShap = [CAShapeLayer layer];// 從貝茲路徑取到形狀 circleShap.path = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:radius].CGPath;// 雖然得到了形狀, 但是並沒有得到具體的 frame(bounds) 也就是實際上並沒有範圍 只是可以展現動畫的效果 那麼錨點其實就是設定的位置點 circleShap.position = position; if (self.buttonType == DDFlashButtonInner) {# 在這裡設定 frame 就是為了滿足我們想要的錨點位置讓動畫效果動起來, 下面也一樣, 可以不設定試試效果就明白了! // circleShap.bounds = CGRectMake(0, 0, radius *2, radius *2); circleShap.frame = CGRectMake(position.x-radius, position.y-radius, radius*2, radius*2); // 線寬 circleShap.lineWidth = 1; // 填充的顏色 不設定預設就給黃色 circleShap.fillColor = self.flashColor ? self.flashColor.CGColor:[UIColor yellowColor].CGColor; }else { circleShap.frame = self.bounds; // 線寬 circleShap.lineWidth = 5; circleShap.fillColor = [UIColor clearColor].CGColor; // 邊緣線的顏色 不設定就預設給個紫色 circleShap.strokeColor = self.flashColor ? self.flashColor.CGColor:[UIColor purpleColor].CGColor; } // 不透明度 要設定成透明的 不然內部風格的時候會畫出來圖案點點 circleShap.opacity = 0; return circleShap;}
第 7 步 : 把點擊的事件完成就 OK 了
- (void)didTap:(UITapGestureRecognizer *)tapGesture{// 擷取點擊點的位置 CGPoint tapLocation = [tapGesture locationInView:self];// 定義一個圖層 下面分情況去給予不同形狀 CAShapeLayer *circleShape = nil;// 預設一個變化比例 1 倍 CGFloat scale = 1.0f;// 擷取 View 的寬和高 CGFloat width = self.bounds.size.width, height = self.bounds.size.height; if (self.buttonType == DDFlashButtonInner) {# 這裡就是在視圖內部效果, 就是以點擊的點為圓心 畫一個小圓(這裡是半徑為1) 然後讓它動畫起來 (不斷的變大並變透明) 所以放大倍數只要能到最大的變就行了 不一定非要這樣寫, 你開心就好! CGFloat biggerEdge = width > height ? width :height; CGFloat radius = 1 scale = biggerEdge / radius + 0.5;# 調用方法獲得圖層 錨點位置就是點擊的位置circleShape = [self creatCircleShapWithPostion:CGPointMake(tapLocation.x , tapLocation.y ) pathRect:CGRectMake(0, 0, radius * 2, radius * 2) radius:radius]; }else {# 這個是外部動畫效果 設定能放大5.5倍 scale = 5.5f;# 錨點位置在 View 的中心 這個圖層和 View 是一樣的形狀範圍 circleShape = [self creatCircleShapWithPostion:CGPointMake(width /2 , height / 2) pathRect:self.bounds radius:self.layer.cornerRadius]; }// view圖層 上添加 有形狀的自訂圖層 [self.layer addSublayer:circleShape];# 給自訂圖層添加動畫 [circleShape addAnimation:[self createFlashAnimationWisthScale:scale duration:1.0f] forKey:nil];}
最後說一句: 用的時候在 viewController 中引入, 建立自訂的 View 執行個體對象, 改變傳入的風格和顏色就可以展示效果了!
iOS基礎-動畫效果的總結--(CALayer — 粉骨碎身全不怕,要留清白在人間!<小拳石>動畫的思維導圖基礎知識:iOS能夠實現動畫的方式:(如上圖)UIView基礎實現方式一UIView基礎實現方式二CoreAnimation實現方式動畫的效果簡述:傳達狀態提高使用者對直接操作的感知協助使用者可視化操作的結果UIVIew的基礎動畫:UIKit直接將動畫繼承到UIView類中,當內部的一些屬性發生改變時,UIView將為這些改變提供動畫支援.執行動畫的工作由UIView類自動完成,但希望在...
原文連結:http://www.jianshu.com/p/c187c7005ce1
著作權歸作者所有,轉載請聯絡作者獲得授權,並標註“簡書作者”。