标签:
一、动画块
frame bounds center alpha Transition(过渡) transform(动画效果)
我们之前使用过的UIView动画 其实本质上也是 CoreAnimation实现的,之上对它里面的动画进行了封装
视图支持动画的属性有 frame bounds center alpha transform 以及动画的延时 动画的曲线(淡入淡出,动画过渡) 重复次数
+ (void)setAnimationDelegate:(id)delegate;
+ (void)setAnimationWillStartSelector:(SEL)selector 当动画即将开始时,执行delegate对象的selector,并且把beginAnimations:context:中传入的参数传进selector
+ (void)setAnimationDidStopSelector:(SEL)selector 当动画结束时,执行delegate对象的selector,并且把beginAnimations:context:中传入的参数传进selector
+ (void)setAnimationDuration:(NSTimeInterval)duration 动画的持续时间,秒为单位
+ (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;
}];
二、图层
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;
}
三、图层动画
- (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;
}
四、动画锚点
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;
}
五、核心动画
在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保持动画最后的状态
六、显式动画
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"];
}
七、关键帧动画
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];
}
八、核心动画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)];
}
九、动力效果
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;
}
十、动力效果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];
}
标签:
原文地址:http://www.cnblogs.com/fshmjl/p/4852357.html