UIKit Dynamics其实就是UIKit对一些物理学行为仿真的封装。使用UIKit动力学对常用的iOS动画CoreAnimation、UIView animations进行补充。
我们应该了解的基本概念:
- UIDynamicItem:用来描述一个力学物体的状态,其实就是实现了UIDynamicItem委托的对象。从iOS 7.0开始,UIView和UICollectionViewLayoutAttributes默认实现该协议。如果自定义的对象实现了该协议,即可通过Dynamic Animator实现物理仿真。
- UIDynamicBehavior:动力行为的描述,用来指定UIDynamicItem应该如何运动,即定义适用的物理规则。一般我们使用这个类的子类对象来对一组UIDynamicItem应该遵守的行为规则进行描述。
- UIDynamicAnimator:动画的播放者,动力行为(UIDynamicBehavior)的容器,添加到容器内的行为将发挥作用。
- ReferenceView:等同于力学参考系,只有当想要添加力学行为的UIView是ReferenceView的子view时,动力UI才发生作用。
UIKit动力学行为包括:UIGravityBehavior(重力),UICollisionBehavior(碰撞),UIAttachmentBehavior(吸附),UISnapBehavior(捕捉),UIPushBehavior(推动)以及辅助行为UIDynamicItemBehavior。所有的UIDynamicBehavior都是可以独立作用,同时也遵守力的合成。也就是说,组合使用行为可以实现一些较复杂的效果。
1. UIDynamicItemBehavior:辅助的行为,用来设置运动学元素参与物理仿真过程中的参数,如:弹性系数、摩擦系数、密度、阻力、角阻力以及是否允许旋转等。
elasticity(弹性系数):决定了碰撞的弹性程度,比如碰撞时物体的弹性
friction(摩擦系数) :决定了沿接触面滑动时的摩擦力大小
density(密度): 跟size结合使用,计算物体的总质量。质量越大,物体加速或减速就越困难
resistance(阻力):决定线性移动的阻力大小,与摩擦系数不同,摩擦系数只作用于滑动运动
angularResistance(角阻力) :决定旋转运动时的阻力大小
allowsRotation(允许旋转):这个属性很有意思,它在真实的物理世界没有对应的模型。设置这个属性为 NO 物体就完全不会转动,而无论施加多大的转动力
扫描二维码关注公众号,回复: 2578185 查看本文章
2. UIGravityBehavior:重力行为
// 实例化重力行为
UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:self.imageViews];
// 将重力行为添加至仿真者
[self.animator addBehavior:gravityBehavior];
3. UICollisionBehavior:碰撞行为
// 移除所有动力学行为
[self.animator removeAllBehaviors];
// 添加重力行为
UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:self.imageViews];
[self.animator addBehavior:gravityBehavior];
// 初始化碰撞行为
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:self.imageViews];
//
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
/* 设置碰撞模式
UICollisionBehaviorModeItems 与其他对象碰撞
UICollisionBehaviorModeBoundaries 与设置的边框碰撞
UICollisionBehaviorModeEverything 上边两种情况都碰撞
*/
collisionBehavior.collisionMode = UICollisionBehaviorModeEverything;
// 设置碰撞行为代理
collisionBehavior.collisionDelegate = self;
[self.animator addBehavior:collisionBehavior];
// 添加附属行为
UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:self.imageViews];
// 弹力系数 0 ~ 1
itemBehavior.elasticity = 0.8;
[self.animator addBehavior:itemBehavior];
3. UIAttachmentBehavior:附着行为 1. 附着行为描述一个视图与一个锚点或者另一个视图相连接的情况
2. 附着行为描述的是两点之间的连接情况,可以模拟刚性或者弹性连接
3.在多个物体间设定多个UIAttachmentBehavior,可以模拟多物体连接
4. 属性:
attachedBehaviorType:连接类型(连接到锚点或视图)
items:连接视图数组
anchorPoint:连接锚点
length:距离连接锚点的距离
只要设置了以下两个属性,即为弹性连接
damping:振幅大小
frequency:振动频率
- (void)performAttachmentBehavior
{
if (self.animator == nil) {
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
} else {
[self.animator removeAllBehaviors];
}
for (int i = 0; i < self.imageViews.count; i++) {
CGRect frame = CGRectMake(20 + i * 60, 400, 50, 50);
[self.imageViews[i] setFrame:frame];
}
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(attachmentBechaviorPanGesture:)];
[self.view addGestureRecognizer:panGestureRecognizer];
for (int i = 0; i < self.imageViews.count - 1; i++) {
UIAttachmentBehavior *attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:self.imageViews[i] attachedToItem:self.imageViews[i + 1]];
attachmentBehavior.frequency = 0.8;
attachmentBehavior.damping = 0.5;
attachmentBehavior.length = 50;
[self.animator addBehavior:attachmentBehavior];
}
}
- (void)attachmentBechaviorPanGesture:(UIPanGestureRecognizer *)gesture
{
CGPoint location = [gesture locationInView:self.view];
if (gesture.state == UIGestureRecognizerStateBegan) {
// [(UIImageView *) self.imageViews[0] setCenter:loction];
[self initDragBehaviourWithAnchorPosition:location];
[self.animator addBehavior:self.dragBehavior];
}else if (gesture.state == UIGestureRecognizerStateChanged) {
[self.dragBehavior setAnchorPoint:location];
} else if (gesture.state == UIGestureRecognizerStateEnded){
// 移除所有动力学行为
[self.animator removeAllBehaviors];
// 添加重力行为
UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:self.imageViews];
[self.animator addBehavior:gravityBehavior];
// 初始化碰撞行为
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:self.imageViews];
//
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
/* 设置碰撞模式
UICollisionBehaviorModeItems 与其他对象碰撞
UICollisionBehaviorModeBoundaries 与设置的边框碰撞
UICollisionBehaviorModeEverything 上边两种情况都碰撞
*/
collisionBehavior.collisionMode = UICollisionBehaviorModeEverything;
// 设置碰撞行为代理
collisionBehavior.collisionDelegate = self;
[self.animator addBehavior:collisionBehavior];
// 添加附属行为
UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:self.imageViews];
// 弹力系数 0 ~ 1
itemBehavior.elasticity = 0.8;
[self.animator addBehavior:itemBehavior];
}
}
- (void)initDragBehaviourWithAnchorPosition:(CGPoint)anchorPosition {
UIView *obj = self.imageViews[0];
self.dragBehavior = [[UIAttachmentBehavior alloc] initWithItem:obj attachedToAnchor:anchorPosition];
double length = [self getDistanceBetweenAnchor:anchorPosition andBallView:obj];
[self.dragBehavior setLength:((CGFloat) length < 20) ? (CGFloat) length : 20];
}
- (double)getDistanceBetweenAnchor:(CGPoint)anchor andBallView:(UIView *)ballView {
return sqrt(pow((anchor.x - ballView.center.x), 2.0) + pow((anchor.y - ballView.center.y), 2.0));
}
4. UISnapBehavior:捕捉行为
1.捕捉行为 可以将视图通过动画吸附到某个点上2. 初始化设定一下 UISnapBehavior 的 initWithItem:snapToPoint: 即可
3. 属性:
damping:振幅大小,默认为0.5f
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[view]];
[self.animator addBehavior:gravityBehavior];
UISnapBehavior *snapBehavior = [[UISnapBehavior alloc] initWithItem:view snapToPoint:self.view.center];
snapBehavior.damping = 0.2;
[self.animator addBehavior:snapBehavior];
5. 推动行为:UIPushBehavior
1. 推动行为可以为一个视图施加一个作用力,该力可以是持续的,也可以是一次性的2. 可以设置力的大小,方向和作用点等信息
3. 属性:
•mode :推动类型(一次性或是持续推)
•active :是否激活,如果是一次性推,需要激活
•angle :推动角度
•magnitude :推动力量
初始化的时候有两种模式:UIPushBehaviorModeContinuous(这个模型可以忽略)
- (void)performPushBehavior
{
if (self.centerview == nil) {
self.centerview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 150)];
self.centerview.backgroundColor = [UIColor greenColor];
self.centerview.center = self.view.center;
[self.view addSubview:self.centerview];
}
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureAction:)];
[self.view addGestureRecognizer:panGesture];
}
- (void)panGestureAction:(UIPanGestureRecognizer *) recongnizer
{
CGPoint firsPoint = CGPointZero;
CGPoint endPoint = CGPointZero;
CGPoint location = [recongnizer locationInView:self.view];
if (recongnizer.state == UIGestureRecognizerStateBegan) {
firsPoint = location;
} else if (recongnizer.state == UIGestureRecognizerStateEnded) {
endPoint = location;;
UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[self.centerview] mode:UIPushBehaviorModeInstantaneous
];
pushBehavior.active = YES;
CGFloat distance = sqrtf(powf((endPoint.x - firsPoint.x), 2) + powf(endPoint.y - firsPoint.y, 2));
CGFloat angle = atan2f(endPoint.y - firsPoint.y, endPoint.x - firsPoint.x);
pushBehavior.angle = angle;
pushBehavior.magnitude = distance/100;
// pushBehavior.pushDirection = CGVectorMake(1, 0);
// [pushBehavior setPushDirection:CGVectorMake([recongnizer velocityInView:self.view].x /100.f, 0)];
[self.animator addBehavior:pushBehavior];
} else if (recongnizer.state == UIGestureRecognizerStateEnded) {
}
}
总结:
2. 使用UIKit Dynamics的步凑:
1. 实例化动画的仿真者UIDynamicAnimator,并设置参考视图用于物理仿真。参考视图表示要仿真的范围。
注意:UIDynamicAnimator类的实例需作为成员变量,防止方法执行完后被销毁,每个对象拥有一个UIDynamicAnimator管理其动力学行为。
2. 实例化要仿真的行为,并指定哪些对象遵守该行为。
3. 将要仿真的行为添加至仿真者UIDynamicAnimator,仿真立即开始。
参考文章:
http://blog.csdn.net/gandam19/article/details/19498315
http://www.th7.cn/Program/IOS/201312/166139.shtml