iOS 开发之动力效果
UIDynamic是从iOS 7开始引入的一种新技术属于UIKit框架可以模拟现实生活中的物理现象如碰撞抖动摆动等
1、动力效果会把上一个效果移除
2、动力效果也可以叠加多个效果
使用 UIDynamic步骤:
1、创建一个动力效果器(UIDynamicAnimator)
2、创建动力效果(Behavior)添加到对应的视图上
3、将动力效果添加到动力效果器中
必须遵守了UIDynamicItem这个协议才可以使用动力效果
UIView默认已经遵守了这个协议
UIDynamic提供的动力效果:
1、UIDynamic提供的动力效果
2、UIGravityBehavior:重力效果
3、UICollisionBehavior:碰撞效果
4、UIDynamicItemBehavior:动力元素效果
5、UIPushBehavior:推动效果
6、UISnapBehavior:迅速移动效果
7、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;
1、重力效果 : 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²)重力加速度越大碰撞越厉害
2、碰撞效果 : UICollisionBehavior
可以让物体之间实现碰撞效果
也可以通过添加边界(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;
3、动力元素效果 : UIDynamicItemBehavior
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物体就完全不会转动,而无论施加多大的转动力
4、推动效果 : 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; 推动的方向
5、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)
6、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 幅度
UIGravityBehavior:重力效果
UICollisionBehavior:碰撞效果
UIDynamicItemBehavior:动力元素效果
具体代码如下
#import "ViewController.h"
@interface ViewController ()<UIDynamicAnimatorDelegate,UICollisionBehaviorDelegate>
{
UIDynamicAnimator *dynamicAnimator;
UIView *view1;
UIView *view2;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 动力效果器的类
dynamicAnimator = [ [ UIDynamicAnimator alloc ] initWithReferenceView:self.view ];
// self.view 产生动力效果的有效区域
// 代理方法
dynamicAnimator.delegate = self;
view1 = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
view1.backgroundColor = [UIColor redColor];
view1.center = self.view.center;
[ self.view addSubview:view1 ];
view2 = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
view2.backgroundColor = [UIColor orangeColor];
view2.center = CGPointMake(self.view.center.x+100, self.view.center.y+100);
[ self.view addSubview:view2 ];
}
// 触摸屏幕
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 把之前添加过的效果移除
[ dynamicAnimator removeAllBehaviors ] ;
view1.hidden = NO;
UITouch *touch = [ touches anyObject ];
CGPoint touchPoint = [ touch locationInView:self.view ] ;
view1.center = touchPoint ;
view2.center = CGPointMake(self.view.center.x+100, self.view.center.y+100);
}
// 触摸屏幕结束 添加动力效果并执行
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// 重力效果
// 在 view1 上添加重力效果
UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:@[view1] ];
// 设置 加速度(数值越大 效果越大)
gravity.magnitude = 100;
// 动力效果的方向
// dx 负数向左 正数向右
// dy 负数向上 正数向下
gravity.gravityDirection =CGVectorMake(0, 1);
// 添加到动力效果器 开始动力效果
[dynamicAnimator addBehavior:gravity];
/*
// 边界碰撞效果
// 在 view1 上添加碰撞效果
UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:@[view1] ];
collision.collisionDelegate = self;
// 把动力效果器的范围当做边界
// collision.translatesReferenceBoundsIntoBoundary = YES;
// 添加两个点 连成一条线 当做边界
[collision addBoundaryWithIdentifier:@"line1" fromPoint:CGPointMake(0, 300) toPoint:CGPointMake(400, 650)];
// 通过 贝塞尔曲线 画一个圆形
// UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 200, 300, 300)];
// [collision addBoundaryWithIdentifier:@"圆形" forPath:path];
// 添加到动力效果器
[ dynamicAnimator addBehavior:collision ];
*/
// 两个视图之间的碰撞效果
UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:@[view1,view2] ];
collision.collisionDelegate = self;
collision.translatesReferenceBoundsIntoBoundary = YES;
// 如果设置了两个元素之间 相互碰撞 设置了边界也不起作用
collision.collisionMode = UICollisionBehaviorModeEverything;
[ dynamicAnimator addBehavior:collision ];
// 动力元素效果 可以与其他的动力效果 配合使用
UIDynamicItemBehavior *item =[[UIDynamicItemBehavior alloc]initWithItems:@[ view1,view2 ] ];
// 设置元素的跳跃度(0-1)
item.elasticity = 1;
// 摩擦力
item.friction = 0;
// 阻力
item.resistance = 0;
// 角度阻力系数
item.angularResistance = 0;
[dynamicAnimator addBehavior:item];
}
// 碰撞效果 的代理方法(碰撞边界)
- (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
{
// view1.hidden = YES;
}
// 两个物体之间相互碰撞
- (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
{
// view1.hidden = YES;
}
// 重力效果 的代理方法
// 启动
- (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator
{
NSLog(@"启动");
}
// 暂停
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator
{
NSLog(@"暂停");
}
UIPushBehavior:推动效果
UISnapBehavior:迅速移动效果
UIAttachmentBehavior:附着效果
具体代码如下
#import "ViewController.h"
@interface ViewController ()
{
UIDynamicAnimator *dynamicAnimator;
UIView *view1;
UIView *view2;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
dynamicAnimator = [ [ UIDynamicAnimator alloc ] initWithReferenceView:self.view ];
view1 = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
view1.backgroundColor = [UIColor redColor];
view1.center = self.view.center;
[ self.view addSubview:view1 ];
view2 = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
view2.backgroundColor = [UIColor orangeColor];
// view2.center = self.view.center;
[ self.view addSubview:view2 ];
推动效果 : UIPushBehavior
// UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(pushView) ];
// [view1 addGestureRecognizer:tap];
UISnapBehavior:迅速移动效果
// UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(snap:) ];
// [self.view addGestureRecognizer:tap];
// UIAttachmentBehavior:附着效果
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(attachment:) ];
[ self.view addGestureRecognizer:tap ];
}
- (void)attachment:(UITapGestureRecognizer *)sender
{
// 6、UIAttachmentBehavior:附着效果
[dynamicAnimator removeAllBehaviors];
UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc]initWithItem:view1 offsetFromCenter:UIOffsetMake(20, 20) attachedToAnchor:[sender locationInView:self.view ] ];
attachment.length = 35;
attachment.damping = 0.2;
attachment.frequency = 5;
[ dynamicAnimator addBehavior:attachment ] ;
UIAttachmentBehavior *attachment1 = [[UIAttachmentBehavior alloc]initWithItem:view1 offsetFromCenter:UIOffsetMake(20, 20) attachedToItem:view2 offsetFromCenter:UIOffsetMake(20, 20) ];
attachment.length = 35;
attachment.damping = 0.2;
attachment.frequency = 5;
[dynamicAnimator addBehavior:attachment1];
}
- (void)snap:(UITapGestureRecognizer *)sender
{
// 5、UISnapBehavior:迅速移动效果
[dynamicAnimator removeAllBehaviors];
// 迅速移动效果 只能一次 添加到一个元素上 snapToPoint 让他移动到哪一个点
UISnapBehavior *snap = [ [ UISnapBehavior alloc ]initWithItem:view1 snapToPoint:[sender locationInView:self.view ] ];
snap.damping = 0.1;
[dynamicAnimator addBehavior:snap];
}
- (void)pushView
{
[dynamicAnimator removeAllBehaviors];
// 4、推动效果 : UIPushBehavior
UIPushBehavior *push = [[UIPushBehavior alloc]initWithItems:@[view1] mode:UIPushBehaviorModeInstantaneous ];
// UIPushBehaviorModeContinuous,
// UIPushBehaviorModeInstantaneous
// x 正右 负左 y 正下 负上
push.pushDirection = CGVectorMake(1, 0);
push.active = YES;
push.magnitude = 3;
[dynamicAnimator addBehavior:push];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end