1、動畫塊ios
frame bounds center alpha Transition(過渡) transform(動畫效果)express
咱們以前使用過的UIView動畫 其實本質上也是 CoreAnimation實現的,之上對它裏面的動畫進行了封裝數組
視圖支持動畫的屬性有 frame bounds center alpha transform 以及動畫的延時 動畫的曲線(淡入淡出,動畫過渡) 重複次數緩存
+ (void)setAnimationDelegate:(id)delegate;併發
+ (void)setAnimationWillStartSelector:(SEL)selector 當動畫即將開始時,執行delegate對象的selector,而且把beginAnimations:context:中傳入的參數傳進selectorapp
+ (void)setAnimationDidStopSelector:(SEL)selector 當動畫結束時,執行delegate對象的selector,而且把beginAnimations:context:中傳入的參數傳進selector框架
+ (void)setAnimationDuration:(NSTimeInterval)duration 動畫的持續時間,秒爲單位ide
+ (void)setAnimationDelay:(NSTimeInterval)delay 動畫延遲delay秒後再開始函數
+ (void)setAnimationStartDate:(NSDate *)startDate 動畫的開始時間,默認爲now性能
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve 動畫的節奏控制
+ (void)setAnimationRepeatCount:(float)repeatCount 動畫的重複次數
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses 若是設置爲YES,表明動畫每次重複執行的效果會跟上一次相反
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache 設置視圖view的過渡效果, transition指定過渡類型, cache設置YES表明使用視圖緩存,性能較好
// 開始動畫
[UIView beginAnimations:@"ll" context:nil];
// 設置動畫持續時間
[UIView setAnimationDuration:3];
// 具體的動畫效果
imageView.alpha = 0.5;
[UIView setAnimationDuration:3];
imageView.alpha = 1;
// 設置bounds
imageView.bounds = CGRectMake(0, 0, 100, 100);
imageView.center = CGPointMake(50, 300);
// 提交動畫
[UIView commitAnimations];
過渡動畫
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft, 從左面翻轉
UIViewAnimationTransitionFlipFromRight,從右面翻轉
UIViewAnimationTransitionCurlUp, 向上翻頁
UIViewAnimationTransitionCurlDown,向下翻頁
};
過渡狀態
typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
UIViewAnimationCurveEaseInOut, // slow at beginning and end 慢進慢出
UIViewAnimationCurveEaseIn, // slow at beginning 快進
UIViewAnimationCurveEaseOut, // slow at end 快出
UIViewAnimationCurveLinear 勻速
};
還原視圖的初始狀態
[UIView animateWithDuration:3 animations:^{
imageView.transform = CGAffineTransformIdentity;
}];
2、圖層
CoreAnimation 核心動畫 須要導入 QuartCore 框架 (如今不須要)
CALayer(圖層)和UIView 的關係:
在UIView中有一個layer屬性的做爲根視圖層,根圖層沒有隱式動畫,根視圖上能夠放其餘子圖層,在UIView中全部可以看到的內容都包含在layer中
CALayer 負責視圖中的顯示的內容和動畫
UIView 負責監聽和響應事件
CALayer 的存在乎義正在:
在IOS中CALayer的設計主要是爲了內容展和動畫操做、CALayer自己並不包含在UIKit中。他不能響應事件
CALayer的經常使用屬性:
定義一個圖層位置
bounds:圖層的大小
position:圖層的中心點
anchorPoint: 錨點、定位點 錨點的描述是相對於 本身的*x , *y位置比例而言的 默認在圖像中心點(0.5,0.5)的位置 決定圖層的那個點 顯示在中心點位置 是
contents 圖層顯示內容,例如能夠將圖片做爲圖層內容顯示 是
contentsRect 圖層顯示內容的大小和位置 是
cornerRadius 圓角半徑 是
doubleSided 圖層背面是否顯示,默認爲YES 否
frame 圖層大小和位置,不支持隱式動畫,因此CALayer中不多使用frame,一般使用bounds和position代替 否
hidden 是否隱藏 是
mask 圖層蒙版 是
maskToBounds 子圖層是否剪切圖層邊界,默認爲NO 是
opacity 透明度 ,相似於UIView的alpha 是
position 決定圖層在父視圖的位置 圖層位於 *父視圖* 中心點位置,相似於UIView的center 是
shadowColor 陰影顏色 是
shadowOffset 陰影偏移量 是
shadowOpacity 陰影透明度,注意默認爲0,若是設置陰影必須設置此屬性 是
shadowPath 陰影的形狀 是
shadowRadius 陰影模糊半徑 是
sublayers 子圖層 是
sublayerTransform 子圖層形變 是
transform 圖層形變
寫「是」的都支持隱式動畫
以上支持隱式動畫的屬性 本質是這些屬性的變更默認隱含了CABasicAnimation動畫實現
- (void)test1
{
// CALayer和UIView的關係:
// 在UIView中有一個layer屬性做爲根圖層,根圖層上能夠放其餘子圖層,在UIView中全部可以看到的內容都包含在layer中
// CALayer負責視圖中顯示的內容和動畫
// UIView負責監聽和響應事件
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
view.backgroundColor = [UIColor redColor];
[self.view addSubview:view];
// 圖層上不能夠添加監聽和響應事件
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(testResponse:)];
[view addGestureRecognizer:tap];
}
- (void)testResponse:(UITapGestureRecognizer *)sender{
sender.view.layer.cornerRadius = sender.view.layer.cornerRadius == 0 ? 50 : 0;
}
#pragma mark -----------CALayer初體驗---------------
- (void)layerTest1{
myLayer = [[CALayer alloc]init];
myLayer.bounds = CGRectMake(100, 200, 300, 300);
// 設置中心點
myLayer.position = CGPointMake(100, 300);
myLayer.cornerRadius = 150;
myLayer.backgroundColor = [UIColor colorWithRed:1.000 green:0.295 blue:0.384 alpha:1.000].CGColor;
myLayer.borderWidth = 2;
myLayer.borderColor = [UIColor whiteColor].CGColor;
myLayer.shadowColor = [UIColor yellowColor].CGColor;
// 設置陰影顏色 必須設置shadowOpacity 陰影顏色的透明度(默認爲0 徹底透明)
myLayer.shadowOpacity = 1.0;
myLayer.shadowOffset = CGSizeMake(-1, -1);
// 子圖層是添加到根圖層上的
[self.view.layer addSublayer:myLayer];
}
點擊手勢方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
myLayer.position = [touch locationInView:self.view];
// myLayer.backgroundColor = [UIColor yellowColor].CGColor;
CGFloat width = CGRectGetWidth(myLayer.bounds);
width = width == 300 ? 100:300;
myLayer.cornerRadius = width/2;
myLayer.bounds = CGRectMake(0, 0, width, width);
myLayer.backgroundColor = myLayer.backgroundColor == [UIColor redColor].CGColor ? [UIColor colorWithRed:1.000 green:0.336 blue:0.378 alpha:1.000].CGColor : [UIColor redColor].CGColor;
}
3、圖層動畫
- (void)addLayer{
myLayer = [[CALayer alloc]init];
myLayer.backgroundColor = [UIColor colorWithRed:1.000 green:0.037 blue:0.000 alpha:1.000].CGColor;
myLayer.shadowColor = [UIColor colorWithRed:1.000 green:0.950 blue:0.353 alpha:1.000].CGColor;
// 陰影的透明度默認爲0
myLayer.shadowOpacity = 1.0;
myLayer.bounds = CGRectMake(0, 0, width, width);
myLayer.borderWidth = 2;
myLayer.borderColor = [UIColor yellowColor].CGColor;
myLayer.cornerRadius = width/2;
myLayer.shadowRadius = width/2;
myLayer.shadowOffset = CGSizeMake(-1, -1);
myLayer.position = self.view.center;
// myLayer.contents = (id)[UIImage imageNamed:@"touxiang"].CGImage;
// myLayer.masksToBounds = YES;
[self.view.layer addSublayer:myLayer];
}
- (void)addImageLayer{
otherLayer = [[CALayer alloc]init];
otherLayer.bounds = CGRectMake(0, 0, width, width);
otherLayer.contents = (id)[UIImage imageNamed:@"touxiang"].CGImage;
otherLayer.masksToBounds = YES;
otherLayer.position = self.view.center;
otherLayer.borderWidth = 2;
otherLayer.borderColor =[UIColor yellowColor].CGColor;
otherLayer.cornerRadius = width/2;
[self.view.layer addSublayer:otherLayer];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
[self changeFaceWith:[touch locationInView:self.view]];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
[self changeFaceWith:[touch locationInView:self.view]];
}
- (void)changeFaceWith:(CGPoint)point{
myLayer.position = point;
width = width == 100 ? 300 : 100;
myLayer.bounds = CGRectMake(0, 0, width, width);
myLayer.cornerRadius = width/2;
otherLayer.position = point;
otherLayer.bounds = CGRectMake(0, 0, width, width);
otherLayer.cornerRadius= width/2;
}
4、動畫錨點
anchorPoint 錨點 以錨點爲中心執行動畫 (與漁夫定船的效果同樣)
anchorPoint 默認是0.5,0.5 錨點是一個比例
anchorPoint 在左上角的時候爲 0 ,0
anchorPoint 在右上角的時候爲 1 ,0
anchorPoint 在左下角的時候爲 0 ,1
anchorPoint 在右下角的時候爲 1 ,1
- (void)shipLayer{
shipLayer = [[CALayer alloc]init];
shipLayer.backgroundColor = [UIColor brownColor].CGColor;
shipLayer.bounds = CGRectMake(0, 0, 100, 100);
shipLayer.position = self.view.center;
// CALayer 的透明度
shipLayer.opacity = 0.5;
[self.view.layer addSublayer:shipLayer];
NSLog(@"錨點x==%f,錨點y==%f",shipLayer.anchorPoint.x,shipLayer.anchorPoint.y);
APLayer = [[CALayer alloc]init];
APLayer.backgroundColor = [UIColor redColor].CGColor;
APLayer.bounds = CGRectMake(0, 0, 5, 5);
// 經過shipLayer設置APLayer的中心點 position.x = shipLayer的寬*錨點x position.y = shipLayer的高*錨點y
CGFloat x = CGRectGetWidth(shipLayer.bounds)*shipLayer.anchorPoint.x;
CGFloat y = CGRectGetHeight(shipLayer.bounds)*shipLayer.anchorPoint.y;
// CGFloat xScale = x/CGRectGetWidth(self.view.frame);
// CGFloat yScale = y/CGRectGetHeight(self.view.frame);
APLayer.position = CGPointMake( x, y);
[shipLayer addSublayer:APLayer];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
// 經過屏幕的x點/屏幕的寬度 獲得點擊的點 與屏幕的一個比例
CGFloat xScale = touchPoint.x/CGRectGetWidth(self.view.frame);
CGFloat yScale = touchPoint.y/CGRectGetHeight(self.view.frame);
shipLayer.anchorPoint = CGPointMake(xScale, yScale);
// 經過屏幕的y點/屏幕的高度 獲得點擊的點 與屏幕的一個比例
APLayer.position = CGPointMake(CGRectGetWidth(shipLayer.bounds)*shipLayer.anchorPoint.x, CGRectGetHeight(shipLayer.bounds)*shipLayer.anchorPoint.y);
NSLog(@"錨點x==%f,錨點y==%f",shipLayer.anchorPoint.x,shipLayer.anchorPoint.y);
// 角度值經計算轉化爲弧度值 要把角度值轉化爲弧度值 以使用一個簡單的公式Mπ/180;
shipLayer.transform = CATransform3DMakeRotation(45*M_PI/180, 0, 0, 1);//x y z是三個軸 0(不旋轉) 1(爲旋轉)
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
shipLayer.transform = CATransform3DIdentity;
}
5、核心動畫
在ios中分的核心動畫爲幾類:基礎動畫(CABasicAnimation) 關鍵幀動畫(CAKeyframeAnimation) 動畫組(CAAnimationGroup) 轉場動畫 (CATransition)
CAAnimation :核心動畫的基礎類,不能直接使用,負責動畫運行時間、速度的控制、自己實現了CAMediaTiming協議
關鍵幀動畫和基礎動畫的區別:基礎動畫只能從一個點到另外一個點,關鍵幀動畫能夠設置多個點,從第一個點依次到最後一個點
CAPropertyAnimation: 屬性動畫也是基類(經過屬性進行動畫設置,注意是動畫屬性),不能直接使用。
CABasicAnimation:基礎動畫,經過屬性修改進行動畫參數控制,只有初始狀態和結束狀態。
CAKeyframeAnimation:關鍵幀動畫,一樣是經過屬性進行動畫參數控制,可是同基礎動畫不一樣的是它能夠有多個狀態控制。
CAAnimationGroup:動畫組,動畫組是一種組合模式設計,能夠經過動畫組來進行全部動畫行爲的統一控制,組中全部動畫效果能夠併發執行。
CATransition:轉場動畫,主要經過濾鏡進行動畫效果設置。
基礎動畫、關鍵幀動畫都屬於屬性動畫,就是經過修改屬性值產生動畫效果,開發人員只須要設置初始值和結束值,中間的過程動畫(又叫「補間動畫」)由系統自動計算產生,和基礎動畫不一樣的是關鍵幀動畫能夠設置多個屬性值,每兩個屬性中間的補間動畫由系統自動完成,所以從這個角度而言基礎動畫又能夠當作是有兩個關鍵幀的關鍵幀動畫
建立基礎動畫 須要經過fromValue和toValue 屬性來指定一個開始值和結束值 當添加基礎動畫到圖層中的時候,他纔會開始變化
autoreverses:當設定這個屬性爲YES時,在他到達目的地以後,會以動畫的方式返回到開始值
duration 設定開始值到結束值花費的時間 期間會被速度的屬性影響
speed 默認的值爲 1.0.這意味着動畫播放按照默認的速度。若是你改變這個值爲 2.0,動畫會用 2 倍的速度播放。 這樣的影響就是使持續時間減半。若是你指定的持續時間爲 6 秒,速度爲 2.0,動畫就會播放 3 秒鐘---一半的 持續時間
把速度設置成0 就能夠暫停動畫
repeatCount 默認的是 0,意味着動畫只會播放一次 這個不該該和 repeatDration 屬性一塊使用。(負數不是無限循環)
repeatDuration 這個屬性指定了動畫應該被重複多久。動畫會一直重複,直到設定的時間流逝完。它不該該和 repeatCount 一塊兒使用
timingFunction 速度控制函數,控制動畫運行的節奏
timingFunction 屬性值:
kCAMediaTimingFunctionLinear(線性):勻速,給你一個相對靜態的感受
kCAMediaTimingFunctionEaseIn(漸進):動畫緩慢進入,而後加速離開
kCAMediaTimingFunctionEaseOut(漸出):動畫全速進入,而後減速的到達目的地
kCAMediaTimingFunctionEaseInEaseOut(漸進漸出):動畫緩慢的進入,中間加速,而後減速的到達目的地。這個是默認的動畫行爲。
removedOnCompletion 默認爲YES,表明動畫執行完畢後就從圖層上移除,圖形會恢復到動畫執行前的狀態。若是想讓圖層保持顯示動畫執行後的狀態,那就設置爲NO,不過還要設置fillMode爲kCAFillModeForwards
fillMode 設置當前對象在非活動時間段的行爲 好比動畫開始以前或者動畫結束以後
fillMode屬性值(上面提到過 要想fillMode有效,須要設置removedOnCompletion = NO)
kCAFillModeRemoved 這個是默認值,也就是說當動畫開始前和動畫結束後,動畫對layer都沒有影響,動畫結束後,layer會恢復到以前的狀態
kCAFillModeForwards 當動畫結束後,layer會一直保持着動畫最後的狀態
kCAFillModeBackwards 在動畫開始前,只須要將動畫加入了一個layer,layer便當即進入動畫的初始狀態並等待動畫開始。
kCAFillModeBoth 這個其實就是上面兩個的合成.動畫加入後開始以前,layer便處於動畫初始狀態,動畫結束後layer保持動畫最後的狀態
6、顯式動畫
UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"heart" ofType:@"jpg"]];
showLayer = [[CALayer alloc]init];
showLayer.bounds = CGRectMake(0, 0, image.size.width/2, image.size.width/2);
showLayer.position = self.view.center;
showLayer.contents = (id)image.CGImage;
[self.view.layer addSublayer:showLayer];
#pragma mark ----- 改變基礎動畫的中心點(position)------
- (void)anmiation1{
// CABasicAnimation 屬於 屬性動畫 需告訴她 我們改變的屬性是哪一個 (把屬性當作字符串傳遞)
CABasicAnimation *anmiation = [CABasicAnimation animationWithKeyPath:@"position"];
// toValue 設置動畫要道哪一個位置
anmiation.toValue = [NSValue valueWithCGPoint:CGPointMake(400, showLayer.position.y)];
anmiation.duration = 3;//持續時間爲3秒
// 以動畫效果回到初始位置
anmiation.autoreverses = YES;
// 若是使用fillModel必須禁用removedOnCompletion
// anmiation.removedOnCompletion = NO;
// anmiation.fillMode = kCAFillModeBoth;
// 設置 慢進慢出
anmiation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
// 添加動畫到圖層 forKey:動畫的名字,能夠爲空
[showLayer addAnimation:anmiation forKey:@"move"];
}
#pragma mark -------bounds --------
- (void)animation2{
UIImage *image = [UIImage imageNamed:@"touxiang"];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
animation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, image.size.width/1, image.size.width/1)];
animation.duration = 0.5;
animation.autoreverses = YES;
// repeatCount == -1 不是無限循環 HUGE爲無窮大
animation.repeatCount = HUGE;
[showLayer addAnimation:animation forKey:@"jump"];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// [self animation2];
[self addAnimation3];
}
- (void)addAnimation3{
// 基礎動畫繼承至屬性動畫 經過屬性名當作一個key來肯定圍繞哪一個屬性 進行動畫
CABasicAnimation *animation= [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];//設置須要改變的屬性
animation.fromValue = @(-0.07);
animation.toValue = @(0.07);//transform.rotation.z 以z軸爲中心,旋轉1
animation.duration = 0.05;
animation.repeatCount = 2;
// 是否容許以動畫的方式返回
animation.autoreverses = YES;
[showLayer addAnimation:animation forKey:@"zhendon"];
}
- (void)addAnimation4{
// 基礎動畫繼承至屬性動畫 經過屬性名當作一個key來肯定圍繞哪一個屬性 進行動畫
CABasicAnimation *animation= [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];//設置須要改變的屬性
animation.fromValue = @(-0.07);
animation.toValue = @(0.07);//transform.rotation.z 以z軸爲中心,旋轉1
animation.duration = 0.05;
animation.repeatCount = 2;
// 是否容許以動畫的方式返回
animation.autoreverses = YES;
[showLayer addAnimation:animation forKey:@"zhendon"];
}
7、關鍵幀動畫
CAKeyframeAnimation 也屬於 CAPropertyAnimation
關鍵幀動畫 可讓咱們精確的控制動畫效果 它的原理是把動畫序列裏面比較關鍵幀提取出來 設置他的動畫效果
path 屬性 意爲路徑 執行動畫軌跡的路徑
values 屬性 執行動畫軌跡的數組
UIImageView *imageView = [[UIImageView alloc]initWithFrame:[UIScreen mainScreen].bounds];
imageView.image = [UIImage imageNamed:@"hua.jpg"];
[self.view addSubview:imageView];
[self addPetal];
- (void)addPetal{
UIImage *image = [UIImage imageNamed:@"huaban"];
petalLayer = [[CALayer alloc]init];
petalLayer.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
petalLayer.position = CGPointMake(150, 250);
petalLayer.contents = (id)image.CGImage;
[self.view.layer addSublayer:petalLayer];
}
- (void)dropAnimation{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
// animation.fromValue = [NSValue valueWithCGPoint:petalLayer.position];
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(300, 500)];
animation.duration = 5;//持續5秒
animation.removedOnCompletion = NO;//禁用
animation.fillMode = kCAFillModeBoth;
[petalLayer addAnimation:animation forKey:@"drop"];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self dropAnimation];
}
8、核心動畫1
- (void)addHeart{
UIImage *image = [UIImage imageNamed:@"heart.jpg"];
heartLayer = [[CALayer alloc]init];
heartLayer.bounds = CGRectMake(0, 0, image.size.width/4, image.size.height/4);
heartLayer.position = CGPointMake(self.view.center.x, 200);
heartLayer.contents = (id)image.CGImage;
[self.view.layer addSublayer:heartLayer];
}
- (void)petalDrop{
CAKeyframeAnimation *drop = [CAKeyframeAnimation animationWithKeyPath:@"position"];
drop.duration = 5;
// drop.values = @[[self getPointWithX:50 andY:100],[self getPointWithX:60 andY:110],[self getPointWithX:70 andY:130],[self getPointWithX:80 andY:140]];
// 建立路徑
CGMutablePathRef path = CGPathCreateMutable();
// 給路徑添加一個起始點
CGPathMoveToPoint(path, NULL, petalLayer.position.x, petalLayer.position.y);
// 有起始點 能夠經過起始點到另外一個點畫線
CGPathAddLineToPoint(path, NULL, petalLayer.position.x+100, petalLayer.position.y+10);
CGPathAddLineToPoint(path, NULL, petalLayer.position.x-100, petalLayer.position.y+30);
// 關閉路徑
// CGPathCloseSubpath(path);
drop.path = path;
// 釋放路徑
CGPathRelease(path);
path = nil;
drop.removedOnCompletion = NO;
drop.fillMode = kCAFillModeBoth;
[petalLayer addAnimation:drop forKey:@"drop1"];
}
- (void)addAnimation{
// CAKeyframeAnimation 關鍵幀動畫
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
animation.duration = 1;
animation.repeatCount = 1;//HUGE
NSMutableArray *array = [NSMutableArray array];
for (float t=2*M_PI; t > 0; t=t-0.1) {
//經過心形曲線得到 心形曲線上的點
[array addObject: [self getPointWithX:40*(2*cos(t)-cos(2*t)) andY:35*(2*sin(t)-sin(2*t))]];
}
//畫一個心形曲線
animation.values = [array copy];
[heartLayer addAnimation:animation forKey:@"move"];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self addAnimation];
[self petalDrop];
}
- (void)addPetal
{
UIImage *petal = [UIImage imageNamed:@"huaban"];
petalLayer = [[CALayer alloc]init];
petalLayer.bounds = CGRectMake(0, 0, petal.size.width, petal.size.height);
petalLayer.position = CGPointMake(100, 200);
petalLayer.contents = (id)petal.CGImage;
[self.view.layer addSublayer:petalLayer];
}
#pragma mark 把CGPoint轉換成NSValue
- (NSValue *)getPointWithX:(CGFloat)x andY:(CGFloat)y{
return [NSValue valueWithCGPoint:CGPointMake(x+heartLayer.position.x, y+heartLayer.position.y)];
}
9、動力效果
UIDynamic是從iOS7開始引入的一種新技術 屬於UIKit框架 能夠模擬現實生活中的物理現象 如碰撞 抖動 擺動
玩動力效果 如玩電吉他 電吉他有效果器 能夠添加各類電子效果
動力效果 也有一個效果器 叫作 動力效果器 裏面能夠添加 動力效果
電吉他切換效果 會把上一個效果移除
動力效果 也是同樣
電吉他能夠疊加多個效果
動力效果 也是同樣
使用UIDynamic大致步驟:
1、建立一個動力效果器(UIDynamicAnimator)
2、建立動力效果(Behavior)添加到對應的視圖上
3、將動力效果添加到動力效果器中 開始動力效果
必須遵照了UIDynamicItem這個協議纔可使用動力效果
UIView默認已經遵照了UIDynamicItem協議
UIDynamic提供的動力效果
UIGravityBehavior:重力效果
UICollisionBehavior:碰撞效果
UIDynamicItemBehavior:動力元素效果
UIPushBehavior:推進效果
UISnapBehavior:迅速移動效果
UIAttachmentBehavior:附着效果
都繼承自UIDynamicBehavior
動力效果器:UIDynamicAnimator
能夠把UIDynamicAnimator看作動力效果的容器 它制定了動力效果的有效範圍
在初始化的時候能夠指定他的有效範圍
- (instancetype)initWithReferenceView:(UIView*)view;
做用在哪個view上 哪個view就是他產生動力效果的有效範圍
既然是容器 他還能夠添加移除 動力效果
- (void)addBehavior:(UIDynamicBehavior *)behavior; 添加動力效果
- (void)removeBehavior:(UIDynamicBehavior *)behavior; 移除動力效果
- (void)removeAllBehaviors; 移除以前添加過的全部動力效果
動力效果器經常使用的屬性
@property (nonatomic, readonly) UIView* referenceView;做用的區域
@property (nonatomic, readonly, copy) NSArray* behaviors;添加到效果器中的全部效果
@property (nonatomic, readonly, getter = isRunning) BOOL running;是否正在進行
@property (nonatomic, assign) id <UIDynamicAnimatorDelegate> delegate;能夠檢測開始暫停
- (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator;
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator;
Behavior 動力效果
重力效果:UIGravityBehavior
設置重力方向 加速度 讓物體(視圖)朝着重力方向掉落
@property (nonatomic, readonly, copy) NSArray *items;添加到重力效果中的全部效果做用對象
@property (readwrite, nonatomic) CGVector gravityDirection;重力方向(是一個二維向量)以左上角爲座標原點 x 負數向左 正數向右 y 負數向上 正數向下 數字越大 重力效果越大
@property (readwrite, nonatomic) CGFloat angle;重力方向(是一個角度,x軸正方向爲0°,順時針正數,逆時針負數)
@property (readwrite, nonatomic) CGFloat magnitude;量級(用來控制加速度,1.0表明加速度是1000 points /second²)重力加速度越大 碰撞越厲害
可讓物體之間實現碰撞效果
也能夠經過添加邊界(boundary)在邊界實現碰撞效果
邊界相關的方法
- (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath*)bezierPath; 添加一個貝塞爾曲線路徑的邊界
- (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2; 經過添加兩個點連成的線 做爲邊界
- (UIBezierPath*)boundaryWithIdentifier:(id <NSCopying>)identifier; 經過ID找到邊界路徑
- (void)removeBoundaryWithIdentifier:(id <NSCopying>)identifier; 移除ID對應的邊界
@property (nonatomic, readonly, copy) NSArray* boundaryIdentifiers; 邊界數組
- (void)removeAllBoundaries;移除全部邊界
typedef NS_OPTIONS(NSUInteger, UICollisionBehaviorMode) {
UICollisionBehaviorModeItems = 1 << 0,元素碰撞
UICollisionBehaviorModeBoundaries = 1 << 1,邊界碰撞
UICollisionBehaviorModeEverything = NSUIntegerMax 全體碰撞
} NS_ENUM_AVAILABLE_IOS(7_0);
//兩個元素相互碰撞
- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p;
- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2;
// 視圖碰撞邊界的時候 觸發
- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier atPoint:(CGPoint)p;
- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier;
UIDynamicItemBehavior 動力元素效果
能夠設置 動力效果的默認值 是一個輔助的效果 設置運動學元素參與物理效果過程當中的參數 如:彈性係數、摩擦係數、密度、阻力、角阻力以及是否容許旋轉等
經常使用屬性
@property (readwrite, nonatomic) CGFloat elasticity; // Usually between 0 (inelastic) and 1 (collide elastically) 屬性設置碰撞彈性係數 範圍(0.0-1.0)決定了碰撞的彈性程度,好比碰撞時物體的彈性
@property (readwrite, nonatomic) CGFloat friction; // 0 being no friction between objects slide along each other設置摩擦係數 決定了沿接觸面滑動時的摩擦力大小
@property (readwrite, nonatomic) CGFloat density; // 1 by default 密度 跟size相關 計算物體的總質量 質量越大 物體加速或減速就越困難
@property (readwrite, nonatomic) CGFloat resistance; // 0: no velocity damping (阻力):決定線性移動的阻力大小 與摩擦係數不一樣 摩擦係數只做用於滑動運動
@property (readwrite, nonatomic) CGFloat angularResistance; // 0: no angular velocity damping 設置角度阻力系數。(0--CGFLOAT_MAX)決定旋轉運動時的阻力大小
@property (readwrite, nonatomic) BOOL allowsRotation; // force an item to never rotate 設置行爲中的dynamic item是否能夠旋轉 設置這個屬性爲 NO 物體就徹底不會轉動,而不管施加多大的轉動力
// 動力效果
dynamicAnimator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];
// self.view 產生動力效果的有效區域
dynamicAnimator.delegate = self;
view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
view1.center = self.view.center;
view1.backgroundColor = [UIColor redColor];
[self.view addSubview:view1];
view2.center = CGPointMake(self.view.center.x+10, self.view.center.y+10);
view2.backgroundColor = [UIColor redColor];
[self.view addSubview:view2];
#pragma mark 動力效果器代理方法
- (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator{
NSLog(@"啓動");
}
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator{
NSLog(@"暫停");
}
#pragma mark 手指觸摸屏幕時
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
view1.center = touchPoint;
}
#pragma mark 重力效果
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
// 把以前 添加過的動力效果移除
[dynamicAnimator removeAllBehaviors];
// 在View1上添加劇力效果
UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:@[view1]];
// 設置加速度 數值越大 碰撞效果越大
gravity.magnitude = 100;
// 設置動力效果的方向
/*
struct CGVector {
CGFloat dx; 負數向左 正數向右
CGFloat dy; 負數向上 正數向下
};
*/
gravity.gravityDirection = CGVectorMake(0, 1);
// 添加到效果器 開始動力效果
[dynamicAnimator addBehavior:gravity];
#pragma mark 碰撞效果
// 在View1上添加碰撞效果
// UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:@[view1]];
//// 把動力效果器的範圍看成邊界
// collision.translatesReferenceBoundsIntoBoundary = YES;
// collision.collisionDelegate = self;
//// [collision addBoundaryWithIdentifier:@"line0" fromPoint:CGPointMake(280, 80) toPoint:CGPointMake(0, 300)];
//// [collision addBoundaryWithIdentifier:@"line" fromPoint:CGPointMake(0, 300) toPoint:CGPointMake(300, 600)];
// UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 200, 100, 100)];
// [collision addBoundaryWithIdentifier:@"圓形" forPath:path];
// [dynamicAnimator addBehavior:collision];
#pragma mark 兩個視圖之間的碰撞
UICollisionBehavior *collision1 = [[UICollisionBehavior alloc] initWithItems:@[view1,view2]];//,view3,view4,view5,view6,view7,view8
collision1.translatesReferenceBoundsIntoBoundary = YES;
collision1.collisionDelegate = self;
// collision1.collisionMode = UICollisionBehaviorModeEverything;
[dynamicAnimator addBehavior:collision1];
#pragma mark 動力元素效果
// 能夠與其餘的動力效果配合使用
UIDynamicItemBehavior *item = [[UIDynamicItemBehavior alloc] initWithItems:@[view1,view2]];//,view3,view4,view5,view6,view7,view8
item.elasticity = 0.7;//設置元素的跳躍度(值的範圍0 --- 1)
[dynamicAnimator addBehavior:item];
}
#pragma mark 與邊界碰撞
- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier atPoint:(CGPoint)p{
NSLog(@"碰撞隔壁死亡的位置X:%f,Y:%f",p.x,p.y);
}
- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier{
// view2.hidden = YES;
}
#pragma mark 兩個物體間相互碰撞
- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p{
NSLog(@"碰撞隔壁死亡的位置X:%f,Y:%f",p.x,p.y);
}
- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2{
// view2.hidden = YES;
}
10、動力效果1
UIPushBehavior 推進效果
typedef NS_ENUM(NSInteger, UIPushBehaviorMode) {
UIPushBehaviorModeContinuous, 持續的力
UIPushBehaviorModeInstantaneous 瞬間的力
} NS_ENUM_AVAILABLE_IOS(7_0);
@property (nonatomic, readonly) UIPushBehaviorMode mode; 推進效果的樣式
@property (nonatomic, readwrite) BOOL active; 是否激活
@property (readwrite, nonatomic) CGFloat angle; 推進角度
// A continuous force vector with a magnitude of 1.0, applied to a 100 point x 100 point view whose density value is 1.0, results in view acceleration of 100 points per s^2
@property (readwrite, nonatomic) CGFloat magnitude; 推進力量
@property (readwrite, nonatomic) CGVector pushDirection; 推進的方向
------------------------------
UISnapBehavior:迅速移動效果
// The point argument is expressed in the reference coordinate system
- (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point;
迅速移動效果 只能一次 添加到一個元素上 snapToPoint 讓他移動到哪個點
@property (nonatomic, assign) CGFloat damping; // damping value from 0.0 to 1.0. 0.0 is the least oscillation. damping 的範圍是(0.0-1.0)
UIAttachmentBehavior 符着效果
typedef NS_ENUM(NSInteger, UIAttachmentBehaviorType) {
UIAttachmentBehaviorTypeItems, 吸附一個元素
UIAttachmentBehaviorTypeAnchor 吸附一個點
} NS_ENUM_AVAILABLE_IOS(7_0);
設置吸附效果的樣式
@property (readonly, nonatomic) UIAttachmentBehaviorType attachedBehaviorType;
UIAttachmentBehavior:附着效果
吸附着一個視圖 或者一個點 (也能夠多個鏈接)
附着效果 一個視圖與一個錨點或者另外一個視圖相鏈接的狀況
附着行爲描述的是兩點之間的鏈接狀況,能夠模擬剛性或者彈性鏈接
在多個物體間設定多個UIAttachmentBehavior,能夠模擬多物體鏈接
typedef NS_ENUM(NSInteger, UIAttachmentBehaviorType) {
UIAttachmentBehaviorTypeItems, 吸附一個元素
UIAttachmentBehaviorTypeAnchor 吸附一個點
} NS_ENUM_AVAILABLE_IOS(7_0);
設置吸附效果的樣式
@property (readonly, nonatomic) UIAttachmentBehaviorType attachedBehaviorType;
@property (readwrite, nonatomic) CGPoint anchorPoint;錨點
@property (readwrite, nonatomic) CGFloat length;距離 與錨點的距離
@property (readwrite, nonatomic) CGFloat damping; // 1: critical damping 跳躍度
@property (readwrite, nonatomic) CGFloat frequency; // in Hertz 幅度
dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
view = [[UIView alloc] initWithFrame:CGRectMake(50, 50,50, 50)];
view.backgroundColor = [UIColor purpleColor];
[self.view addSubview:view];
view1 = [[UIView alloc] initWithFrame:CGRectMake(150, 150,50, 50)];
view1.backgroundColor = [UIColor colorWithRed:0.300 green:0.334 blue:0.768 alpha:1.000];
[self.view addSubview:view1];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
[self.view addGestureRecognizer:tap];
- (void)tapAction:(UITapGestureRecognizer *)sender{
#pragma mark 推進效果
/* [dynamicAnimator removeAllBehaviors];
UIPushBehavior *push = [[UIPushBehavior alloc] initWithItems:@[view] mode:UIPushBehaviorModeContinuous];
// x是正右 負左 y是正下 負上
push.pushDirection = CGVectorMake(1, 0);
push.magnitude = 5;
push.active = YES;
[dynamicAnimator addBehavior:push];
------------------------------------*/
#pragma mark 迅速移動效果
/* [dynamicAnimator removeAllBehaviors];
UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:view snapToPoint:[sender locationInView:self.view]];
snap.damping = 0;///阻尼值從0.0到1.0。0.0是最低的振盪
[dynamicAnimator addBehavior:snap];
------------------------------------------*/
#pragma mark 吸符效果(吸符一個點)
[dynamicAnimator removeAllBehaviors];
UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:view offsetFromCenter:UIOffsetMake(20, 20) attachedToAnchor:[sender locationInView:self.view]];
attachment.length = 100;
attachment.damping = 0.5;
attachment.frequency = 50;
[dynamicAnimator addBehavior:attachment];
#pragma mark 吸符效果(吸符一個視圖)
// UIAttachmentBehavior *attachment1 = [[UIAttachmentBehavior alloc] initWithItem:view offsetFromCenter:UIOffsetMake(10, 10) attachedToItem:view1 offsetFromCenter:UIOffsetMake(10, 10)];
// attachment1.length = 100;
// attachment1.damping = 0.5;
// attachment1.frequency = 50;
// [dynamicAnimator addBehavior:attachment1];
UIAttachmentBehavior *attachment2 = [[UIAttachmentBehavior alloc] initWithItem:view1 attachedToItem:view];
attachment2.damping = 0.5;
attachment2.frequency = 50;
[dynamicAnimator addBehavior:attachment2];
}