您的位置:首页 > 产品设计 > UI/UE

iOS开发UIKit动力学——UIKit Dynamics

2015-07-01 17:52 441 查看
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 物体就完全不会转动,而无论施加多大的转动力

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) {

}
}


总结:
1. 实例化UIKit Dynamics所有相关的类都是通过allco,init创建的,没有提供类方法。

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: