Core Animation
- Core Animation,中文翻譯為核心動(dòng)畫(huà),它是一組非常強(qiáng)大的動(dòng)畫(huà)處理API,使用它能做出非常炫麗的動(dòng)畫(huà)效果,而且往往是事半功倍。也就是說(shuō),使用少量的代碼就可以實(shí)現(xiàn)非常強(qiáng)大的功能。
- Core Animation可以用在Mac OS X和iOS平臺(tái)。
- Core Animation的動(dòng)畫(huà)執(zhí)行過(guò)程都是在后臺(tái)操作的,不會(huì)阻塞主線程。
- 要注意的是,Core Animation是直接作用在CALayer上的,并非UIView。
Core Animation的使用步驟
- 1.首先得有CALayer
- 2.初始化一個(gè)CAAnimation對(duì)象,并設(shè)置一些動(dòng)畫(huà)相關(guān)屬性
- 3.通過(guò)調(diào)用CALayer的addAnimation:forKey:方法,增加CAAnimation對(duì)象到CALayer中,這樣就能開(kāi)始執(zhí)行動(dòng)畫(huà)了
- 4.通過(guò)調(diào)用CALayer的removeAnimationForKey:方法可以停止CALayer中的動(dòng)畫(huà)
CAAnimation
是所有動(dòng)畫(huà)對(duì)象的父類(lèi),負(fù)責(zé)控制動(dòng)畫(huà)的持續(xù)時(shí)間和速度,是個(gè)抽象類(lèi),不能直接使用,應(yīng)該使用它具體的子類(lèi)
-
屬性說(shuō)明:
duration:動(dòng)畫(huà)的持續(xù)時(shí)間
repeatCount:重復(fù)次數(shù),無(wú)限循環(huán)可以設(shè)置HUGE_VALF或者M(jìn)AXFLOAT
repeatDuration:重復(fù)時(shí)間
removedOnCompletion:默認(rèn)為YES,代表動(dòng)畫(huà)執(zhí)行完畢后就從圖層上移除,圖形會(huì)恢復(fù)到動(dòng)畫(huà)執(zhí)行前的狀態(tài)。如果想讓圖層保持顯示動(dòng)畫(huà)執(zhí)行后的狀態(tài),那就設(shè)置為NO,不過(guò)還要設(shè)置fillMode為kCAFillModeForwards
-
fillMode:決定當(dāng)前對(duì)象在非active時(shí)間段的行為。比如動(dòng)畫(huà)開(kāi)始之前或者動(dòng)畫(huà)結(jié)束之后(要想fillMode有效,最好設(shè)置removedOnCompletion = NO)
- kCAFillModeRemoved 這個(gè)是默認(rèn)值,也就是說(shuō)當(dāng)動(dòng)畫(huà)開(kāi)始前和動(dòng)畫(huà)結(jié)束后,動(dòng)畫(huà)對(duì)layer都沒(méi)有影響,動(dòng)畫(huà)結(jié)束后,layer會(huì)恢復(fù)到之前的狀態(tài)
- kCAFillModeForwards 當(dāng)動(dòng)畫(huà)結(jié)束后,layer會(huì)一直保持著動(dòng)畫(huà)最后的狀態(tài)
- kCAFillModeBackwards 在動(dòng)畫(huà)開(kāi)始前,只需要將動(dòng)畫(huà)加入了一個(gè)layer,layer便立即進(jìn)入動(dòng)畫(huà)的初始狀態(tài)并等待動(dòng)畫(huà)開(kāi)始。
- kCAFillModeBoth 這個(gè)其實(shí)就是上面兩個(gè)的合成.動(dòng)畫(huà)加入后開(kāi)始之前,layer便處于動(dòng)畫(huà)初始狀態(tài),動(dòng)畫(huà)結(jié)束后layer保持動(dòng)畫(huà)最后的狀態(tài)
beginTime:可以用來(lái)設(shè)置動(dòng)畫(huà)延遲執(zhí)行時(shí)間,若想延遲2s,就設(shè)置為CACurrentMediaTime()+2,CACurrentMediaTime()為圖層的當(dāng)前時(shí)間
-
timingFunction:速度控制函數(shù),控制動(dòng)畫(huà)運(yùn)行的節(jié)奏
- kCAMediaTimingFunctionLinear(線性):勻速,給你一個(gè)相對(duì)靜態(tài)的感覺(jué)
- kCAMediaTimingFunctionEaseIn(漸進(jìn)):動(dòng)畫(huà)緩慢進(jìn)入,然后加速離開(kāi)
- kCAMediaTimingFunctionEaseOut(漸出):動(dòng)畫(huà)全速進(jìn)入,然后減速的到達(dá)目的地
- kCAMediaTimingFunctionEaseInEaseOut(漸進(jìn)漸出):動(dòng)畫(huà)緩慢的進(jìn)入,中間加速,然后減速的到達(dá)目的地。這個(gè)是默認(rèn)的動(dòng)畫(huà)行為。
delegate:動(dòng)畫(huà)代理(監(jiān)聽(tīng)動(dòng)畫(huà)開(kāi)始和結(jié)束的狀態(tài))
-(void)animationDidStart:(CAAnimation *)anim;
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
- CALayer上動(dòng)畫(huà)的暫停和恢復(fù)
#pragma mark 暫停CALayer的動(dòng)畫(huà)
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
// 讓CALayer的時(shí)間停止走動(dòng)
layer.speed = 0.0;
// 讓CALayer的時(shí)間停留在pausedTime這個(gè)時(shí)刻
layer.timeOffset = pausedTime;
}
- CALayer上動(dòng)畫(huà)的恢復(fù)
#pragma mark 恢復(fù)CALayer的動(dòng)畫(huà)
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = layer.timeOffset;
// 1. 讓CALayer的時(shí)間繼續(xù)行走
layer.speed = 1.0;
// 2. 取消上次記錄的停留時(shí)刻
layer.timeOffset = 0.0;
// 3. 取消上次設(shè)置的時(shí)間
layer.beginTime = 0.0;
// 4. 計(jì)算暫停的時(shí)間(這里也可以用CACurrentMediaTime()-pausedTime)
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
// 5. 設(shè)置相對(duì)于父坐標(biāo)系的開(kāi)始時(shí)間(往后退timeSincePause)
layer.beginTime = timeSincePause;
}
CABasicAnimation——基本動(dòng)畫(huà)
基本動(dòng)畫(huà),是CAPropertyAnimation的子類(lèi)
屬性說(shuō)明:
fromValue:keyPath相應(yīng)屬性的初始值
toValue:keyPath相應(yīng)屬性的結(jié)束值
動(dòng)畫(huà)過(guò)程說(shuō)明:
隨著動(dòng)畫(huà)的進(jìn)行,在長(zhǎng)度為duration的持續(xù)時(shí)間內(nèi),keyPath相應(yīng)屬性的值從fromValue漸漸地變?yōu)閠oValue
keyPath內(nèi)容是CALayer的可動(dòng)畫(huà)Animatable屬性
果fillMode=kCAFillModeForwards同時(shí)removedOnComletion=NO,那么在動(dòng)畫(huà)執(zhí)行完畢后,圖層會(huì)保持顯示動(dòng)畫(huà)執(zhí)行后的狀態(tài)。但在實(shí)質(zhì)上,圖層的屬性值還是動(dòng)畫(huà)執(zhí)行前的初始值,并沒(méi)有真正被改變。
//位移動(dòng)畫(huà)
CABasicAnimation * positionAnim = [CABasicAnimation animation];
positionAnim.keyPath = @"position";
positionAnim.toValue = [NSValue valueWithCGPoint:CGPointMake(self.positionImageV.center.x+200, self.positionImageV.center.y)];
// 設(shè)置動(dòng)畫(huà)執(zhí)行次數(shù)
positionAnim.repeatCount = MAXFLOAT;
// 取消動(dòng)畫(huà)反彈
// 設(shè)置動(dòng)畫(huà)完成的時(shí)候不要移除動(dòng)畫(huà)
positionAnim.removedOnCompletion = NO;
// 設(shè)置動(dòng)畫(huà)執(zhí)行完成要保持最新的效果
positionAnim.fillMode = kCAFillModeForwards;
positionAnim.duration =2;
[self.positionImageV.layer addAnimation:positionAnim forKey:nil];
//創(chuàng)建一個(gè)基本形變動(dòng)畫(huà)
CABasicAnimation * scaleAnim = [CABasicAnimation animation];
//kvc設(shè)置需要?jiǎng)赢?huà)的屬性
scaleAnim.keyPath = @"transform.scale";
//設(shè)置該屬性的最終裝填
scaleAnim.toValue = @0.5;
// 設(shè)置動(dòng)畫(huà)執(zhí)行次數(shù)
scaleAnim.repeatCount = MAXFLOAT;
// 取消動(dòng)畫(huà)反彈
// 設(shè)置動(dòng)畫(huà)完成的時(shí)候不要移除動(dòng)畫(huà)
scaleAnim.removedOnCompletion = NO;
// 設(shè)置動(dòng)畫(huà)執(zhí)行完成要保持最新的效果
scaleAnim.fillMode = kCAFillModeForwards;
//設(shè)置動(dòng)畫(huà)時(shí)間
scaleAnim.duration =2;
[self.scaleImageV.layer addAnimation:scaleAnim forKey:nil];
//旋轉(zhuǎn)動(dòng)畫(huà)
CABasicAnimation * rotationAnim = [CABasicAnimation animation];
rotationAnim.keyPath = @"transform.rotation";
rotationAnim.toValue = @M_PI;
// 設(shè)置動(dòng)畫(huà)執(zhí)行次數(shù)
rotationAnim.repeatCount = MAXFLOAT;
// 取消動(dòng)畫(huà)反彈
// 設(shè)置動(dòng)畫(huà)完成的時(shí)候不要移除動(dòng)畫(huà)
rotationAnim.removedOnCompletion = NO;
// 設(shè)置動(dòng)畫(huà)執(zhí)行完成要保持最新的效果
rotationAnim.fillMode = kCAFillModeForwards;
rotationAnim.duration =2;
[self.rotationImageV.layer addAnimation:rotationAnim forKey:nil];
CAKeyframeAnimation——關(guān)鍵幀動(dòng)畫(huà)
關(guān)鍵幀動(dòng)畫(huà),也是CAPropertyAnimation的子類(lèi),與CABasicAnimation的區(qū)別是:
CABasicAnimation只能從一個(gè)數(shù)值(fromValue)變到另一個(gè)數(shù)值(toValue),而CAKeyframeAnimation會(huì)使用一個(gè)NSArray保存這些數(shù)值
屬性說(shuō)明:
values:上述的NSArray對(duì)象。里面的元素稱(chēng)為“關(guān)鍵幀”(keyframe)。動(dòng)畫(huà)對(duì)象會(huì)在指定的時(shí)間(duration)內(nèi),依次顯示values數(shù)組中的每一個(gè)關(guān)鍵幀
path:可以設(shè)置一個(gè)CGPathRef、CGMutablePathRef,讓圖層按照路徑軌跡移動(dòng)。path只對(duì)CALayer的anchorPoint和position起作用。如果設(shè)置了path,那么values將被忽略
keyTimes:可以為對(duì)應(yīng)的關(guān)鍵幀指定對(duì)應(yīng)的時(shí)間點(diǎn),其取值范圍為0到1.0,keyTimes中的每一個(gè)時(shí)間值都對(duì)應(yīng)values中的每一幀。如果沒(méi)有設(shè)置keyTimes,各個(gè)關(guān)鍵幀的時(shí)間是平分的
一個(gè)關(guān)鍵幀動(dòng)畫(huà)的小例子,在一個(gè)view畫(huà)板上,手指隨意畫(huà)動(dòng)軌跡,圖片通過(guò)關(guān)鍵幀動(dòng)畫(huà)在這軌跡上移動(dòng)
自定一個(gè)DrawView,在DrawView上添加一張圖片
實(shí)現(xiàn)DrawView內(nèi)部的方法
1 手指剛觸碰到view時(shí)
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//獲取touch對(duì)象
UITouch * touch = [touches anyObject];
//獲取手指位置
CGPoint fingerP = [touch locationInView:self];
//創(chuàng)建一個(gè)路徑并保存
UIBezierPath * path = [UIBezierPath bezierPath];
self.path = path;
//路徑添加起點(diǎn)
[path moveToPoint:fingerP];
}
2 手指在view上移動(dòng)時(shí)
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch * touch = [touches anyObject];
CGPoint fingerP = [touch locationInView:self];
//不斷連線,
[self.path addLineToPoint:fingerP];
[self setNeedsDisplay];
}
3 手指離開(kāi)view時(shí)
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//創(chuàng)建一個(gè)幀動(dòng)畫(huà)
CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
//動(dòng)畫(huà)需要改變的屬性
anim.keyPath = @"position";
//動(dòng)畫(huà)的改變的路徑
anim.path = _path.CGPath;
//動(dòng)畫(huà)的時(shí)間
anim.duration = 1;
//動(dòng)畫(huà)的重復(fù)次數(shù)
anim.repeatCount = MAXFLOAT;
[[[self.subviews firstObject] layer] addAnimation:anim forKey:nil];
}
4 重繪方法drawRect
-(void)drawRect:(CGRect)rect{
//劃線
[self.path stroke];
}
- CAKeyframeAnimation.jpeg
CAAnimationGroup——?jiǎng)赢?huà)組
- 動(dòng)畫(huà)組,是CAAnimation的子類(lèi),可以保存一組動(dòng)畫(huà)對(duì)象,將CAAnimationGroup對(duì)象加入層后,組中所有動(dòng)畫(huà)對(duì)象可以同時(shí)并發(fā)運(yùn)行
- 屬性說(shuō)明:
- animations:用來(lái)保存一組動(dòng)畫(huà)對(duì)象的NSArray
- 默認(rèn)情況下,一組動(dòng)畫(huà)對(duì)象是同時(shí)運(yùn)行的,也可以通過(guò)設(shè)置動(dòng)畫(huà)對(duì)象的beginTime屬性來(lái)更改動(dòng)畫(huà)的開(kāi)始時(shí)間
// 同時(shí)縮放,平移,旋轉(zhuǎn)
//創(chuàng)建一個(gè)動(dòng)畫(huà)組
CAAnimationGroup *group = [CAAnimationGroup animation];
//形變動(dòng)畫(huà)
CABasicAnimation *scale = [CABasicAnimation animation];
scale.keyPath = @"transform.scale";
scale.toValue = @0.5;
//旋轉(zhuǎn)動(dòng)畫(huà)
CABasicAnimation *rotation = [CABasicAnimation animation];
rotation.keyPath = @"transform.rotation";
rotation.toValue = @(M_PI);
//位移動(dòng)畫(huà)
CABasicAnimation *position = [CABasicAnimation animation];
position.keyPath = @"position";
position.toValue = [NSValue valueWithCGPoint:CGPointMake(self.imageView.center.x+200,self.imageView.center.y)];
//動(dòng)畫(huà)組時(shí)間
group.duration = 2;
//動(dòng)畫(huà)組重復(fù)
group.repeatCount = MAXFLOAT;
//三個(gè)基本動(dòng)畫(huà)添加到動(dòng)畫(huà)組中
group.animations = @[scale,rotation,position];
[self.imageView.layer addAnimation:group forKey:nil];
}
轉(zhuǎn)場(chǎng)動(dòng)畫(huà)——CATransition
- CATransition是CAAnimation的子類(lèi),用于做轉(zhuǎn)場(chǎng)動(dòng)畫(huà),能夠?yàn)閷犹峁┮瞥銎聊缓鸵迫肫聊坏膭?dòng)畫(huà)效果。iOS比Mac OS X的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)效果少一點(diǎn)
- UINavigationController就是通過(guò)CATransition實(shí)現(xiàn)了將控制器的視圖推入屏幕的動(dòng)畫(huà)效果
- 動(dòng)畫(huà)屬性:
- type:動(dòng)畫(huà)過(guò)渡類(lèi)型
- fade 交叉淡化過(guò)渡
- push 新視圖把舊視圖推出去
- moveIn 新視圖移到舊視圖上面
- reveal 將舊視圖移開(kāi),顯示下面的新視圖
- cube 立方體翻滾效果
- oglFlip 上下左右翻轉(zhuǎn)效果
- suckEffect 收縮效果,如一塊布被抽走
- rippleEffect 水滴效果
- pageCurl 向上翻頁(yè)效果
- pageUnCurl 向下翻頁(yè)效果
- cameraIrisHollowOpen 相機(jī)鏡頭打開(kāi)效果
- cameraIrisHollowClose 相機(jī)鏡頭關(guān)閉效果
- subtype:動(dòng)畫(huà)過(guò)渡方向
- startProgress:動(dòng)畫(huà)起點(diǎn)(在整體動(dòng)畫(huà)的百分比)
- endProgress:動(dòng)畫(huà)終點(diǎn)(在整體動(dòng)畫(huà)的百分比)
- 一個(gè)imageView切換圖片的轉(zhuǎn)場(chǎng)實(shí)現(xiàn)
// 加載圖片名稱(chēng)
NSString *imageN = [NSString stringWithFormat:@"%d",i];
_imageView.image = [UIImage imageNamed:imageN];
i++;
// 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
CATransition *anim = [CATransition animation];
//動(dòng)畫(huà)設(shè)置代理
anim.delegate = self;
//動(dòng)畫(huà)類(lèi)型 蘋(píng)果封裝好多種類(lèi)型
anim.type = @"pageCurl";
anim.duration = 2;
[_imageView.layer addAnimation:anim forKey:nil];

使用UIView動(dòng)畫(huà)函數(shù)實(shí)現(xiàn)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
- 單視圖
- duration:動(dòng)畫(huà)的持續(xù)時(shí)間
- view:需要進(jìn)行轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的視圖
- options:轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的類(lèi)型
- animations:將改變視圖屬性的代碼放在這個(gè)block中
- completion:動(dòng)畫(huà)結(jié)束后,會(huì)自動(dòng)調(diào)用這個(gè)block
+(void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;
- 雙視圖
- duration:動(dòng)畫(huà)的持續(xù)時(shí)間
- options:轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的類(lèi)型
- animations:將改變視圖屬性的代碼放在這個(gè)block中
- completion:動(dòng)畫(huà)結(jié)束后,會(huì)自動(dòng)調(diào)用這個(gè)block
+(void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion;
CADisplayLink
- CADisplayLink是一種以屏幕刷新頻率觸發(fā)的時(shí)鐘機(jī)制,每秒鐘執(zhí)行大約60次左右
- CADisplayLink是一個(gè)計(jì)時(shí)器,可以使繪圖代碼與視圖的刷新頻率保持同步,而NSTimer無(wú)法確保計(jì)時(shí)器實(shí)際被觸發(fā)的準(zhǔn)確時(shí)間
- 使用方法:
- 定義CADisplayLink并制定觸發(fā)調(diào)用方法
- 將顯示鏈接添加到主運(yùn)行循環(huán)隊(duì)列
// 創(chuàng)建定時(shí)器
// [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(timeChange)];
// 添加主運(yùn)行循環(huán)
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
隱式動(dòng)畫(huà)
每一個(gè)UIView內(nèi)部都默認(rèn)關(guān)聯(lián)著一個(gè)CALayer,我們可用稱(chēng)這個(gè)Layer為Root Layer(根層)
所有的非Root Layer,也就是手動(dòng)創(chuàng)建的CALayer對(duì)象,都存在著隱式動(dòng)畫(huà)
列舉幾個(gè)常見(jiàn)的Animatable Properties:
bounds:用于設(shè)置CALayer的寬度和高度。修改這個(gè)屬性會(huì)產(chǎn)生縮放動(dòng)畫(huà)
backgroundColor:用于設(shè)置CALayer的背景色。修改這個(gè)屬性會(huì)產(chǎn)生背景色的漸變動(dòng)畫(huà)
position:用于設(shè)置CALayer的位置。修改這個(gè)屬性會(huì)產(chǎn)生平移動(dòng)畫(huà)
CALayer的屬性
//寬度和高度
@property CGRect bounds;
//位置(默認(rèn)指中點(diǎn),具體由anchorPoint決定)
@property CGPoint position;
//錨點(diǎn)(x,y的范圍都是0-1),決定了position的含義
@property CGPoint anchorPoint;
//背景顏色(CGColorRef類(lèi)型)
@property CGColorRef backgroundColor;
//形變屬性
@property CATransform3D transform;
//邊框顏色(CGColorRef類(lèi)型)
@property CGColorRef borderColor;
//邊框?qū)挾?@property CGFloat borderWidth;
//圓角半徑
@property CGColorRef borderColor;
//內(nèi)容(比如設(shè)置為圖片CGImageRef)
@property(retain) id contents;
- position和anchorPoint
- CALayer有2個(gè)非常重要的屬性:position和anchorPoint
//用來(lái)設(shè)置CALayer在父層中的位置
//以父層的左上角為原點(diǎn)(0, 0)
@property CGPoint position;
//稱(chēng)為“定位點(diǎn)”、“錨點(diǎn)”
//決定著CALayer身上的哪個(gè)點(diǎn)會(huì)在position屬性所指的位置
//以自己的左上角為原點(diǎn)(0, 0)
//它的x、y取值范圍都是0~1,默認(rèn)值為(0.5, 0.5)
@property CGPoint anchorPoint;
- 一個(gè)layer層隨機(jī)變化的例子
- 手動(dòng)創(chuàng)建一個(gè)layer
//創(chuàng)建一個(gè)圖層 (只有新創(chuàng)建的圖層才可以有隱式動(dòng)畫(huà))
CALayer * layer = [[CALayer alloc] init];
//設(shè)置大小
layer.bounds = CGRectMake(0, 0, 80, 80);
//設(shè)置顏色
layer.backgroundColor = [self randomColor].CGColor;
//設(shè)置位置點(diǎn)
layer.position = CGPointMake(200, 150);
//圖層加載到view上
[self.view.layer addSublayer:layer];
self.layer = layer;
- 循環(huán)調(diào)用這個(gè)方法你會(huì)發(fā)現(xiàn)很好玩的隱式動(dòng)畫(huà)
#define angle2radion(angle) angle / 180 * M_PI
-(void)beginAnimation{
//3D旋轉(zhuǎn)
self.layer.transform = CATransform3DMakeRotation(angle2radion(arc4random_uniform(360)), 0, 0, 1);
//3D移動(dòng)
self.layer.position = CGPointMake(arc4random_uniform(200)+20, arc4random_uniform(400)+50);
self.layer.cornerRadius = arc4random_uniform(50);
self.layer.backgroundColor = [self randomColor].CGColor;
self.layer.borderColor = [self randomColor].CGColor;
self.layer.borderWidth = arc4random_uniform(10);
}
//隨機(jī)產(chǎn)生顏色
-(UIColor *)randomColor{
CGFloat r = arc4random_uniform(256) / 255.0;
CGFloat g = arc4random_uniform(256) / 255.0;
CGFloat b = arc4random_uniform(256) / 255.0;
return [UIColor colorWithRed:r green:g blue:b alpha:1];
}
轉(zhuǎn)盤(pán)效果
- 十二星座即為十二個(gè)按鈕
- 把十二個(gè)按鈕重疊加載一起,然后進(jìn)行旋轉(zhuǎn),得到圓形布局的而效果
#pragma mark - xib加載后創(chuàng)建12個(gè)按鈕
-(void)awakeFromNib{
[super awakeFromNib];
//設(shè)置按鈕父控件可以交互
self.rotationView.userInteractionEnabled = YES;
//按鈕的寬高
CGFloat btnW = 68;
CGFloat btnH = 143;
//view的寬高
CGFloat wh = self.bounds.size.width;
//12張按鈕圖片是連一起的一張大圖 需要裁剪
UIImage *bigImage = [UIImage imageNamed:@"LuckyAstrology"];
//select狀太下的圖片
UIImage *selBigImage = [UIImage imageNamed:@"LuckyAstrologyPressed"];
//獲取像素與點(diǎn)的比值
CGFloat scale = [UIScreen mainScreen].scale;
//每個(gè)圖片的寬度
CGFloat imageW = bigImage.size.width / 12 * scale;
//每個(gè)圖片的高度
CGFloat imageH = bigImage.size.height * scale;
for (int i = 0; i < 12; i ++) {
//每個(gè)圖片需要旋轉(zhuǎn)的角度
CGFloat angle = (30 * i) / 180.0 * M_PI;
//自定義按鈕
TurnBtn * btn = [TurnBtn buttonWithType:UIButtonTypeCustom];
//大小
btn.bounds = CGRectMake(0, 0, btnW, btnH);
//設(shè)置position 和anchorPoint 因?yàn)橐D(zhuǎn)每個(gè)按鈕
btn.layer.anchorPoint = CGPointMake(0.5, 1);
btn.layer.position = CGPointMake(wh*0.5, wh*0.5);
//旋轉(zhuǎn)angle
btn.transform = CGAffineTransformMakeRotation(angle);
[self.rotationView addSubview:btn];
//圖片裁剪區(qū)域
CGRect clipR = CGRectMake(i * imageW, 0, imageW, imageH);
//獲得裁剪后的圖片
CGImageRef imgR = CGImageCreateWithImageInRect(bigImage.CGImage, clipR);
//轉(zhuǎn)成UIImage
UIImage *image = [UIImage imageWithCGImage:imgR];
[btn setImage:image forState:UIControlStateNormal];
imgR = CGImageCreateWithImageInRect(selBigImage.CGImage, clipR);
image = [UIImage imageWithCGImage:imgR];
[btn setImage:image forState:UIControlStateSelected];
//設(shè)置背景圖
[btn setBackgroundImage:[UIImage imageNamed:@"LuckyRototeSelected"] forState:UIControlStateSelected];
[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
if (i == 0) {
//默認(rèn)選中第一張
[self btnClick:btn];
}
}
}
- 加載一個(gè)定時(shí)器CADisplayLink,旋轉(zhuǎn)轉(zhuǎn)盤(pán)
#pragma mark -定時(shí)器懶加載
// 1.搞個(gè)定時(shí)器,每隔一段時(shí)間就旋轉(zhuǎn)一定的角度,1秒旋轉(zhuǎn)45°
-(CADisplayLink *)link{
if (!_link) {
//CADisplayLink 定時(shí)器一秒調(diào)用60次
_link = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotation)];
//講定時(shí)器添加到駐訓(xùn)華
[_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
return _link;
}
#pragma mark - 定時(shí)器綁定的旋轉(zhuǎn)方法
-(void)rotation{
// 每一次調(diào)用旋轉(zhuǎn)多少 45 \ 60.0
CGFloat angle = (45 / 60.0) * M_PI / 180.0;
self.rotationView.transform = CGAffineTransformRotate(self.rotationView.transform, angle);
}
#pragma mark - 開(kāi)始旋轉(zhuǎn)的方法
-(void)start{
self.link.paused = NO;
}
#pragma mark - 暫停旋轉(zhuǎn)的方法
-(void)purase {
self.link.paused = YES;
}
- 點(diǎn)擊選號(hào)按鈕,將轉(zhuǎn)盤(pán)快速旋轉(zhuǎn),并且當(dāng)前選中的星座停留在最上方
#pragma mark -選號(hào)點(diǎn)擊
-(IBAction)pickerClick:(id)sender {
// 不需要定時(shí)器旋轉(zhuǎn)
self.link.paused = YES;
// 中間的轉(zhuǎn)盤(pán)快速的旋轉(zhuǎn),并且不需要與用戶(hù)交互
CABasicAnimation *anim = [CABasicAnimation animation];
anim.keyPath = @"transform.rotation";
anim.toValue = @(M_PI * 2 * 3);
anim.duration = 0.5;
anim.delegate = self;
[self.rotationView.layer addAnimation:anim forKey:nil];
// 點(diǎn)擊哪個(gè)星座,就把當(dāng)前星座指向中心點(diǎn)上面
// M_PI 3.14
// 根據(jù)選中的按鈕獲取旋轉(zhuǎn)的度數(shù),
// 通過(guò)transform獲取角度
CGFloat angle = atan2(self.btn.transform.b, self.btn.transform.a);
// 旋轉(zhuǎn)轉(zhuǎn)盤(pán)
self.rotationView.transform = CGAffineTransformMakeRotation(-angle);
}
- 轉(zhuǎn)盤(pán).jpeg
圖片折疊
- 如何制作圖片折疊效果?
把一張圖片分成兩部分顯示,上面一部分,下面一部分,折疊上面部分的內(nèi)容。 - 如何把一張圖片分成兩部分顯示。
搞兩個(gè)控件,一個(gè)顯示上半部分,一個(gè)顯示下半部分,需要用到Layer(圖層)的一個(gè)屬性contentsRect,這個(gè)屬性是可以控制圖片顯示的尺寸,可以讓圖片只顯示上部分或者下部分,注意:取值范圍是0~1.
CGRectMake(0, 0, 1, 0.5) :表示顯示上半部分
CGRectMake(0, 0.5, 1, 0.5) :表示顯示下半部分
-(void)setImage:(UIImage *)image{
_image = image;
//給兩張圖片賦值
self.topImageV.image = _image;
//讓上部圖片只顯示圖片的上部分
self.topImageV.layer.contentsRect = CGRectMake(0, 0, 1, 0.5);
self.bottomImageV.image = _image;
//讓下部圖片只顯示圖片的下部分
self.bottomImageV.layer.contentsRect = CGRectMake(0, 0.5, 1, 0.5);
}
- 如何快速的把兩部分拼接成一張完整的圖片。
- 首先了解折疊,折疊其實(shí)就是旋轉(zhuǎn),既然需要旋轉(zhuǎn)就需要明確錨點(diǎn),因?yàn)槟J(rèn)都是繞著錨點(diǎn)旋轉(zhuǎn)的。
- 上部分內(nèi)容繞著底部中心旋轉(zhuǎn),所以設(shè)置上部分的錨點(diǎn)為(0.5,1)
- 錨點(diǎn)設(shè)置好了,就可以確定位置了.
- 可以把上下部分重合在一起,然后分別設(shè)置上下部分的錨點(diǎn),
上部分的錨點(diǎn)為(0.5,1),下部分的錨點(diǎn)為(0.5,0),就能快速重疊了。
//兩張重疊的圖片設(shè)置錨點(diǎn)
self.topImageV.layer.anchorPoint = CGPointMake(0.5, 1);
self.bottomImageV.layer.anchorPoint = CGPointMake(0.5, 0);
- 如何折疊上部分內(nèi)容。
- 在拖動(dòng)視圖的時(shí)候,旋轉(zhuǎn)上部分控件。修改
transform屬性。 - 可以在上部分和下部分底部添加一個(gè)拖動(dòng)控件(
拖動(dòng)控件尺寸就是完整的圖片尺寸),給這個(gè)控件添加一個(gè)pan手勢(shì),就能制造一個(gè)假象,拖動(dòng)控件的時(shí)候,折疊圖片。 - 計(jì)算Y軸每偏移一點(diǎn),需要旋轉(zhuǎn)多少角度,假設(shè)完整圖片尺寸高度為200,當(dāng)y = 200時(shí),上部分圖片應(yīng)該剛好旋轉(zhuǎn)180°,因此
angle = offsetY * M_PI / 200; - 上部分內(nèi)容應(yīng)該是繞著X軸旋轉(zhuǎn),
逆時(shí)針旋轉(zhuǎn),因此角度需要為負(fù)數(shù)。 - 為了讓折疊效果更加有效果,更加具有立體感,可以給形變?cè)O(shè)置m34屬性,就能添加立體感。
- 反彈效果
當(dāng)手指抬起的時(shí)候,應(yīng)該把折疊圖片還原,其實(shí)就是把形變清空。 - 陰影效果
- 當(dāng)折疊圖片的時(shí)候,底部應(yīng)該有個(gè)陰影漸變過(guò)程。
- 利用
CAGradientLayer(漸變圖層)制作陰影效果,添加到底部視圖上,并且一開(kāi)始需要隱藏,在拖動(dòng)的時(shí)候慢慢顯示出來(lái)。
//漸變圖層
CAGradientLayer * gradientL = [CAGradientLayer layer];
gradientL.frame = self.bottomImageV.bounds;
//漸變顏色數(shù)組
gradientL.colors = @[(id)[UIColor clearColor].CGColor,(id)[UIColor blackColor].CGColor];
gradientL.opacity = 0;
self.gradientL = gradientL;
//添加到底部imageView
[self.bottomImageV.layer addSublayer:gradientL];
- 顏色應(yīng)是由
透明到黑色漸變,表示陰影從無(wú)到有。 - 在拖動(dòng)的時(shí)候計(jì)算不透明度值,假設(shè)拖動(dòng)200,陰影完全顯示,不透明度應(yīng)該為1,因此 opacity = y軸偏移量 * 1 / 200.0;
- 在手指抬起的時(shí)候,需要把陰影設(shè)置隱藏,不透明度為0;
-(void)pan:(UIPanGestureRecognizer *)pan{
//獲得手指偏移量
CGPoint curP = [pan translationInView:self];
//根據(jù)手指偏移量設(shè)置3D旋轉(zhuǎn)角度
CGFloat angle = - curP.y / self.frame.size.height * M_PI;
//復(fù)位
CATransform3D transfrom = CATransform3DIdentity;
// 增加旋轉(zhuǎn)的立體感,近大遠(yuǎn)小,d:距離圖層的距離
transfrom.m34 = -1 / 500.0;
//3D旋轉(zhuǎn)
transfrom = CATransform3DRotate(transfrom, angle, 1, 0, 0);
//旋轉(zhuǎn)上部圖片
self.topImageV.layer.transform = transfrom;
//設(shè)置漸變圖層的透明度
self.gradientL.opacity = curP.y * 1.0 / self.frame.size.height;
//手勢(shì)結(jié)束時(shí)
if (pan.state == UIGestureRecognizerStateEnded) {
//彈簧效果的物理動(dòng)畫(huà)
[UIView animateWithDuration:0.25 delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:10 options:UIViewAnimationOptionCurveEaseInOut animations:^{
//恢復(fù)頂部圖片
self.topImageV.layer.transform = CATransform3DIdentity;
//隱藏漸變圖層
self.gradientL.opacity = 0;
} completion:^(BOOL finished) {
}];
}
}
- 圖片折疊.jpeg
復(fù)制圖層CAReplicatorLayer
- 什么是CAReplicatorLayer?
一種可以復(fù)制自己子層的layer,并且復(fù)制出來(lái)的layer和原生子層有同樣的屬性,位置,形變,動(dòng)畫(huà)。 - CAReplicatorLayer屬性
-
instanceCount: 子層總數(shù)(包括原生子層) -
instanceDelay: 復(fù)制子層動(dòng)畫(huà)延遲時(shí)長(zhǎng) -
instanceTransform: 復(fù)制子層形變(不包括原生子層),每個(gè)復(fù)制子層都是相對(duì)上一個(gè)。 -
instanceColor: 子層顏色,會(huì)和原生子層背景色沖突,因此二者選其一設(shè)置。 -
instanceRedOffset、instanceGreenOffset、instanceBlueOffset、instanceAlphaOffset: 顏色通道偏移量,每個(gè)復(fù)制子層都是相對(duì)上一個(gè)的偏移量。
音量振動(dòng)條
- 首先創(chuàng)建復(fù)制CAReplicatorLayer,音樂(lè)振動(dòng)條layer添加到復(fù)制CAReplicatorLayer上,然后復(fù)制子層就好了。
/創(chuàng)建一個(gè)復(fù)制圖層
CAReplicatorLayer * repL = [CAReplicatorLayer layer];
//設(shè)置復(fù)制圖層的大小
repL.frame = self.bounds;
//添加復(fù)制圖層
[self.layer addSublayer:repL];
- 先創(chuàng)建一個(gè)音量振動(dòng)條,并且設(shè)置好動(dòng)畫(huà),動(dòng)畫(huà)是繞著底部縮放,設(shè)置錨點(diǎn)
//創(chuàng)建一個(gè)圖層
CALayer * layer = [CALayer layer];
//設(shè)置這個(gè)的位置
layer.position = CGPointMake(15, self.frame.size.height);
//設(shè)置圖層的錨點(diǎn)
layer.anchorPoint = CGPointMake(0.5, 1);
//設(shè)置背景顏色
layer.backgroundColor = [UIColor grayColor].CGColor;
//設(shè)置大小
layer.bounds = CGRectMake(0, 0, 30, 150);
//把這個(gè)圖層添加到復(fù)制圖層中
[repL addSublayer:layer];
//創(chuàng)建一個(gè)動(dòng)畫(huà)
CABasicAnimation * anim = [CABasicAnimation animation];
anim.keyPath = @"transform.scale.y";
anim.toValue = @0.1;
anim.repeatCount = MAXFLOAT;
//動(dòng)畫(huà)回到原始位置
anim.autoreverses = YES;
//把動(dòng)畫(huà)加載到layer上
[layer addAnimation:anim forKey:nil];
- 復(fù)制子層
//給復(fù)制圖層中子圖層設(shè)置transform便宜,每個(gè)圖層沿x便宜45
repL.instanceTransform = CATransform3DMakeTranslation(45, 0, 0);
//復(fù)制4個(gè)圖層 包括復(fù)制圖層
repL.instanceCount = 4;
//每個(gè)圖層一個(gè)比一個(gè)延遲一秒執(zhí)行動(dòng)畫(huà)
repL.instanceDelay = 0.1;
//每個(gè)圖層的顏色
repL.instanceColor = [UIColor greenColor].CGColor;
//每個(gè)圖層顏色漸變,
repL.instanceGreenOffset = -0.03;
指示器
- 創(chuàng)建復(fù)制圖層
//創(chuàng)建一個(gè)復(fù)制圖層
CAReplicatorLayer * repL = [CAReplicatorLayer layer];
//設(shè)置圖層的的大小
repL.frame = self.bounds;
//添加復(fù)制圖層
[self.layer addSublayer:repL];
- 創(chuàng)建一個(gè)矩形圖層,設(shè)置縮放動(dòng)畫(huà)。
//創(chuàng)建一個(gè)子圖層
CALayer * layer = [CALayer layer];
//設(shè)置初始位置
layer.position = CGPointMake(self.frame.size.width * 0.5, 10);
//設(shè)置子圖層大小
layer.bounds = CGRectMake(0, 0, 5, 5);
//設(shè)置圖層的背景顏色
layer.backgroundColor = [UIColor purpleColor].CGColor;
//默認(rèn)形變?yōu)?是不顯示的
layer.transform = CATransform3DMakeScale(0, 0, 0);
//把圖層添加到復(fù)制圖層中
[repL addSublayer:layer];
//創(chuàng)建一個(gè)動(dòng)畫(huà)
CABasicAnimation * anim = [CABasicAnimation animation];
//設(shè)置形變
anim.keyPath = @"transform.scale";
anim.fromValue = @1;
anim.toValue = @0;
anim.repeatCount = MAXFLOAT;
CGFloat duration = 1;
anim.duration = duration;
[layer addAnimation:anim forKey:nil];
- 復(fù)制矩形圖層,并且設(shè)置每個(gè)復(fù)制層的角度形變
//20個(gè)子圖層
repL.instanceCount = count;
repL.instanceDelay = duration / count;
//每個(gè)子圖層transform旋轉(zhuǎn)偏移
CGFloat angle = M_PI * 2 / count;
repL.instanceTransform = CATransform3DMakeRotation(angle, 0, 0, 1);
- 設(shè)置復(fù)制動(dòng)畫(huà)延長(zhǎng)時(shí)間(需要保證第一個(gè)執(zhí)行完畢之后,繞一圈剛好又是從第一個(gè)執(zhí)行,因此需要把動(dòng)畫(huà)時(shí)長(zhǎng)平均分給每個(gè)子層)公式:延長(zhǎng)時(shí)間 = 動(dòng)畫(huà)時(shí)長(zhǎng) / 子層總數(shù)
repL.instanceDelay = duration / count;假設(shè)有兩個(gè)圖層,動(dòng)畫(huà)時(shí)間為1秒,延長(zhǎng)時(shí)間就為0.5秒。當(dāng)?shù)谝粋€(gè)動(dòng)畫(huà)執(zhí)行到一半的時(shí)候(0.5),第二個(gè)開(kāi)始執(zhí)行。第二個(gè)執(zhí)行完
倒影效果
- 用復(fù)制圖層實(shí)現(xiàn),搞個(gè)UIImageView展示圖片,然后復(fù)制UIImageView.
- 注意:
復(fù)制圖層只能復(fù)制子層,但是UIImageView只有一個(gè)主層,并沒(méi)有子層,因此不能直接復(fù)制UIImageView. - 正確做法:應(yīng)該把UIImageView添加到一個(gè)UIView上,然后復(fù)制UIView的層,就能復(fù)制UIImageView.
- 注意:
默認(rèn)A控件是B控件的子控件,那么A控件的層就是B控件的層的子層。 - 但是有問(wèn)題,默認(rèn)UIView的層不是復(fù)制層,我們想把UIView的層變成復(fù)制層,重寫(xiě)+layerClass方法。
+(Class)layerClass
{
return [CAReplicatorLayer class];
}
- 倒影效果:就是就是把復(fù)制圖片旋轉(zhuǎn)180度,然后往下平移,最好先偏移在,在旋轉(zhuǎn)。
CAReplicatorLayer *layer = (CAReplicatorLayer *)self.layer;
layer.anchorPoint = CGPointMake(0.5, 1);
layer.instanceCount = 3;
// 往下面平移控件的高度
layer.instanceTransform = CATransform3DMakeRotation(M_PI*0.5, 1, 0, 0);
layer.instanceAlphaOffset = -0.1;
layer.instanceBlueOffset = -0.1;
layer.instanceGreenOffset = -0.1;
layer.instanceRedOffset = -0.1;
- 復(fù)制圖層.jpeg
仿QQ消息提醒(粘性效果)
- 自定義大圓控件(UILabel)
- 讓大圓控件隨著手指移動(dòng)而移動(dòng)
- 注意不能根據(jù)形變修改大圓的位置,只能通過(guò)center,因?yàn)槿潭夹枰玫街行狞c(diǎn)計(jì)算。
//消息按鈕跟隨手指移動(dòng)
CGPoint tranP = [pan translationInView:self];
CGPoint center = self.center;
center.x += tranP.x;
center.y += tranP.y;
self.center = center;
[pan setTranslation:CGPointZero inView:self];
- 在拖動(dòng)的時(shí)候,添加一個(gè)小圓控件在原來(lái)大圓控件的位置
//計(jì)算拖動(dòng)圓與原位置占位圓之間的距離
CGFloat d = [self circleCenterDistanceWithBigCircleCenter:self.center smallCircleCenter:self.backSmallView.center];
//根據(jù)距離縮小占位圓
CGFloat h = self.bounds.size.height*0.5;
CGFloat smallRadius = h - d / 10;
self.backSmallView.bounds = CGRectMake(0, 0, smallRadius * 2, smallRadius * 2);
self.backSmallView.layer.cornerRadius = smallRadius;
#pragma mark - 計(jì)算兩個(gè)圓心之間的距離
-(CGFloat)circleCenterDistanceWithBigCircleCenter:(CGPoint)bigCircleCenter smallCircleCenter:(CGPoint)smallCircleCenter
{
CGFloat offsetX = bigCircleCenter.x - smallCircleCenter.x;
CGFloat offsetY = bigCircleCenter.y - smallCircleCenter.y;
return sqrt(offsetX * offsetX + offsetY * offsetY);
}
- 注意這個(gè)小圓控件并不會(huì)隨著手指移動(dòng)而移動(dòng),因此應(yīng)該添加到父控件上
- 一開(kāi)始設(shè)置中心點(diǎn)和尺寸和大圓控件一樣。
- 隨著大圓拖動(dòng),小圓半徑不斷減少,可以根據(jù)兩個(gè)圓心的距離,隨便生成一段比例,隨著圓心距離增加,圓心半徑不斷減少。
- 每次小圓改變,需要重新設(shè)置小圓的尺寸和圓角半徑。
- 粘性效果
- 就是在兩圓之間繪制一個(gè)形變矩形,描述形變矩形路徑。
#pragma mark - 不規(guī)則矩形圖層(根據(jù)路徑創(chuàng)建的圖層) 懶加載
-(CAShapeLayer *)shapeLayer
{
if (_shapeLayer == nil) {
// 展示不規(guī)則矩形,通過(guò)不規(guī)則矩形路徑生成一個(gè)圖層
CAShapeLayer *layer = [CAShapeLayer layer];
_shapeLayer = layer;
layer.fillColor = self.backgroundColor.CGColor;
[self.superview.layer insertSublayer:layer below:self.layer];
}
return _shapeLayer;
}
- 這里需要用到CAShapeLayer,可以根據(jù)一個(gè)路徑,生成一個(gè)圖層,展示出來(lái)。把形變圖層添加到父控件并且顯示在小圓圖層下就OK了。
self.shapeLayer.path = [self pathWithBigCirCleView:self smallCirCleView:self.backSmallView].CGPath;因?yàn)樗杏?jì)算出來(lái)的點(diǎn),都是基于父控件。
-注意:這里不能用繪圖,因?yàn)槔L圖內(nèi)容只要超過(guò)當(dāng)前控件尺寸就不會(huì)顯示,但是當(dāng)前形變矩形必須顯示在控件之外
粘性計(jì)算圖.png
#pragma mark - 描述兩圓之間一條矩形路徑
-(UIBezierPath *)pathWithBigCirCleView:(UIView *)bigCirCleView smallCirCleView:(UIView *)smallCirCleView
{
CGPoint bigCenter = bigCirCleView.center;
CGFloat x2 = bigCenter.x;
CGFloat y2 = bigCenter.y;
CGFloat r2 = bigCirCleView.bounds.size.width / 2;
CGPoint smallCenter = smallCirCleView.center;
CGFloat x1 = smallCenter.x;
CGFloat y1 = smallCenter.y;
CGFloat r1 = smallCirCleView.bounds.size.width / 2;
// 獲取圓心距離
CGFloat d = [self circleCenterDistanceWithBigCircleCenter:bigCenter smallCircleCenter:smallCenter];
CGFloat sinθ = (x2 - x1) / d;
CGFloat cosθ = (y2 - y1) / d;
// 坐標(biāo)系基于父控件
CGPoint pointA = CGPointMake(x1 - r1 * cosθ , y1 + r1 * sinθ);
CGPoint pointB = CGPointMake(x1 + r1 * cosθ , y1 - r1 * sinθ);
CGPoint pointC = CGPointMake(x2 + r2 * cosθ , y2 - r2 * sinθ);
CGPoint pointD = CGPointMake(x2 - r2 * cosθ , y2 + r2 * sinθ);
CGPoint pointO = CGPointMake(pointA.x + d / 2 * sinθ , pointA.y + d / 2 * cosθ);
CGPoint pointP = CGPointMake(pointB.x + d / 2 * sinθ , pointB.y + d / 2 * cosθ);
UIBezierPath *path = [UIBezierPath bezierPath];
// A
[path moveToPoint:pointA];
// AB
[path addLineToPoint:pointB];
// 繪制BC曲線
[path addQuadCurveToPoint:pointC controlPoint:pointP];
// CD
[path addLineToPoint:pointD];
// 繪制DA曲線
[path addQuadCurveToPoint:pointA controlPoint:pointO];
return path;
}
- 粘性業(yè)務(wù)邏輯處理
- 當(dāng)圓心距離超過(guò)100,就不需要描述形變矩形(并且把之前的形變矩形移除父層),小圓也需要隱藏。
- 沒(méi)有超過(guò)100,則相反。
- 手指停止拖動(dòng)業(yè)務(wù)邏輯
- 判斷下圓心是否超過(guò)100,超過(guò)就播放爆炸效果,添加個(gè)UIImageView在當(dāng)前控件上,并且需要取消控制器view的自動(dòng)布局。
- 沒(méi)有超過(guò),就還原。
#pragma mark - 手勢(shì)事件
-(void)pan:(UIPanGestureRecognizer *)pan{
//消息按鈕跟隨手指移動(dòng)
CGPoint tranP = [pan translationInView:self];
CGPoint center = self.center;
center.x += tranP.x;
center.y += tranP.y;
self.center = center;
[pan setTranslation:CGPointZero inView:self];
//計(jì)算拖動(dòng)圓與原位置占位圓之間的距離
CGFloat d = [self circleCenterDistanceWithBigCircleCenter:self.center smallCircleCenter:self.backSmallView.center];
//根據(jù)距離縮小占位圓
CGFloat h = self.bounds.size.height*0.5;
CGFloat smallRadius = h - d / 10;
self.backSmallView.bounds = CGRectMake(0, 0, smallRadius * 2, smallRadius * 2);
self.backSmallView.layer.cornerRadius = smallRadius;
if (d > kMaxDistance) {
//當(dāng)距離超過(guò)規(guī)定距離時(shí)
// 可以拖出來(lái)
// 隱藏占位圓
self.backSmallView.hidden = YES;
// 移除不規(guī)則的矩形
[self.shapeLayer removeFromSuperlayer];
self.shapeLayer = nil;
}else if(d > 0 && self.backSmallView.hidden == NO){
// 有圓心距離,并且圓心距離不大,才需要展示
// 展示不規(guī)則矩形,通過(guò)不規(guī)則矩形路徑生成一個(gè)圖層
self.shapeLayer.path = [self pathWithBigCirCleView:self smallCirCleView:self.backSmallView].CGPath;
}
//手勢(shì)結(jié)束時(shí) 即手松開(kāi)時(shí)
if (pan.state == UIGestureRecognizerStateEnded) {
if (d > kMaxDistance) {
// 當(dāng)圓心距離大于規(guī)定距離
// 展示gif動(dòng)畫(huà)
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.bounds];
NSMutableArray *arrM = [NSMutableArray array];
for (int i = 11; i < 19; i++) {
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%d",i]];
[arrM addObject:image];
}
imageView.animationImages = arrM;
imageView.animationRepeatCount = 1;
imageView.animationDuration = 0.5;
[imageView startAnimating];
[self addSubview:imageView];
//延遲執(zhí)行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self removeFromSuperview];
});
}else{
// 當(dāng)圓心距離大于最大圓心距離
// 移除不規(guī)則矩形
[self.shapeLayer removeFromSuperlayer];
self.shapeLayer = nil;
// 還原位置
[UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:0 options:UIViewAnimationOptionCurveLinear animations:^{
// 設(shè)置大圓中心點(diǎn)位置
self.center = self.backSmallView.center;
} completion:^(BOOL finished) {
// 顯示小圓
self.backSmallView.hidden = NO;
}];
}
}
}





