iOS开发之 UIDynamic (动力效果)

一、UIDynamic入门须知

UIDynamic 是从iOS7 开始引入的一种新技术,属于UIKit框架,可以模拟现实生活中的物理现象,如碰撞、抖动、摆动等

 

 1⃣️、动力效果就像是玩电吉他,电吉他有效果器 可以添加各种电子效果.动力效果,也有一个效果器,叫做动力效果器,里面可以添加动力效果

 电吉他切换效果,会把上一个效果移除。动力效果也是一样

 

 2⃣️、使用UIDynamic 的步骤:

 1、创建一个动力效果器(UIDynamicAnimator)

 2、创建动力效果(Behavior)添加到对应的视图上

 3、将动力效果添加到动力效果器中 开始动力效果

 

 必须遵守了UIDynamicItem这个协议才可以使用动力效果 UIView默认已经遵守了这个协议

 

 3⃣️、UIDynamic提供的动力效果

 1UIGravityBehavior:重力效果

 2UICollisionBehavior:碰撞效果

 3UIDynamicItemBehavior:动力元素效果

 4UIPushBehavior:推动效果

 5UISnapBehavior:迅速移动效果

 6UIAttachmentBehavior:附着效果

 都继承自UIDynamicBehavior

 

 4⃣️、动力效果器:UIDynamicAnimator

 可以把UIDynamicAnimator看做动力效果的容器 它制定了动力效果的有效范围

 在初始化的时候可以指定他的有效范围

 - (instancetype)initWithReferenceView:(UIView*)view;

 作用在哪一个view 哪一个view就是他产生动力效果的有效范围

 

 既然是容器  他还可以添加移除 动力效果

 - (void)addBehavior:(UIDynamicBehavior *)behavior; 添加动力效果

 - (void)removeBehavior:(UIDynamicBehavior *)behavior; 移除动力效果

 - (void)removeAllBehaviors; 移除之前添加过的所有动力效果

 

5⃣️、 动力效果器常用的属性

 @property (nonatomic, readonly) UIView* referenceView;作用的区域

 @property (nonatomic, readonly, copy) NSArray* behaviors;添加到效果器中的所有效果

 @property (nonatomic, readonly, getter = isRunning) BOOL running;是否正在进行

 @property (nonatomic, assign) id delegate;可以检测开始暂停

 - (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator; // 开始的时候调用

 - (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator;// 暂停的时候调用



二、重力效果器

重力效果:UIGravityBehavior

 设置重力方向,加速度,让物体(视图)朝着重力方向掉落

 

 @property (nonatomic, readonly, copy) NSArray *items;添加到重力效果中的所有效果作用对象

 @property (readwrite, nonatomic) CGVector gravityDirection;重力方向(是一个二维向量)以左上角为坐标原点 x 负数向左 正数向右  y 负数向上  正数向下  数字越大  重力效果越大

 @property (readwrite, nonatomic) CGFloat angle;重力方向(是一个角度,x轴正方向为,顺时针正数,逆时针负数)

 @property (readwrite, nonatomic) CGFloat magnitude;量级(用来控制加速度,1.0代表加速度是1000 points /second²)重力加速度越大 碰撞越厉害


1、初始化动力效果器和两个视图

   dynamicAnimator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];
    //    self.view 产生动力效果的有效区域
    
    view1 = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
    view1.center = self.view.center;
    view1.backgroundColor = [UIColor redColor];
    [self.view addSubview:view1];
    
    view2 = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
    view2.center = CGPointMake(self.view.center.x+100, self.view.center.y+100);
    view2.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:view2];


2、在我们触摸屏幕的时候把view1的位置换为触摸的位置

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)even
{
    //    把之前添加的动力效果 移除
    [dynamicAnimator removeAllBehaviors];
    
    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); 
}


3、触摸结束的时候 添加动力效果并执行
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//    把之前添加的动力效果 移除
    [dynamicAnimator removeAllBehaviors];
    
//    在view1上添加重力效果
    UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:@[view1]];
    
//    设置加速度 数值越大,碰撞效果越大
    gravity.magnitude = 9.8;
    /*
    struct CGVector {
    CGFloat dx;  负数向左,正数向右
    CGFloat dy;  负数向上,正数向下
};
    */
//    设置动力效果的方向
    gravity.gravityDirection = CGVectorMake(0, 1);
    
    [dynamicAnimator addBehavior:gravity];
}
 
  
三、碰撞效果

可以让物体之间实现碰撞效果:UICollisionBehavior

 也可以通过添加边界(boundary)在边界实现碰撞效果

 

 边界相关的方法

 - (void)addBoundaryWithIdentifier:(id )identifier forPath:(UIBezierPath*)bezierPath; 添加一个贝塞尔曲线路径的边界

 - (void)addBoundaryWithIdentifier:(id )identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2; 通过添加两个点连成的线 作为边界

 - (UIBezierPath*)boundaryWithIdentifier:(id )identifier; 通过ID找到边界路径

 - (void)removeBoundaryWithIdentifier:(id )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);



我们在上面不是初始化了两个视图吗,现在就可以用到另外一个视图view2了,我们让view1碰撞view2

和重力效果器的步骤差不多,其实我们可以同时给self。view 添加多种动力效果,我们就直接在重力效果的基础上添加吧,步骤都一样,我们只需要在第三步结束之后再添加一个碰撞效果就可以

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [dynamicAnimator removeAllBehaviors]; 
//    在view1上添加重力效果
    UIGravityBehavior *gravity = [[UIGravityBehavior alloc]initWithItems:@[view1]];
    gravity.magnitude = 9.8;
    gravity.gravityDirection = CGVectorMake(0, 1);  
    [dynamicAnimator addBehavior:gravity];
  
#pragma mark ----------碰撞效果 
    /*
    UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:@[view1]];
    collision.collisionDelegate = self;
    
//    通过两个点 划一条线当做边界
//    [collision addBoundaryWithIdentifier:@"line1" fromPoint:CGPointMake(0, 300) toPoint:CGPointMake(400, 600)];
    
//    通过贝塞尔曲线 画一个圆
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 200, 300, 300)];
    [collision addBoundaryWithIdentifier:@"圆形" forPath:path];
    
//    把动力效果器的范围 当做边界
//    collision.translatesReferenceBoundsIntoBoundary = YES;
    [dynamicAnimator addBehavior:collision];
     */
    
    
//    两个视图之间相互碰撞
    UICollisionBehavior *collision = [[UICollisionBehavior alloc]initWithItems:@[view1,view2]];
//    把动力效果器的范围 当做边界
    collision.translatesReferenceBoundsIntoBoundary = YES;
//    如果设置了两个元素之间 相互碰撞 设置了边界也不起作用
//    collision.collisionMode = UICollisionBehaviorModeItems;
    collision.collisionDelegate = self;
    
    [dynamicAnimator addBehavior:collision];
}
 
   
  大家也可以试试我注释掉的代码,看看会出现什么碰撞效果。 
  

四、动力元素效果 

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 物体就完全不会转动,而无论施加多大的转动力


- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
#pragma mark  ------------动力元素效果 ————————————————
//    可以与其他的 动力效果 配合使用
    UIDynamicItemBehavior *item = [[UIDynamicItemBehavior alloc]initWithItems:@[view1,view2]];
//    设置元素的跳跃度(0-1)
    item.elasticity = 1;
    item.friction = 0; // 设置摩擦力为0
    item.resistance = 0; // 设置阻力为0
    item.angularResistance = 0; // 设置阻力系数为0
    [dynamicAnimator addBehavior:item]; // 添加到动力效果器上
}
在我们把动力元素效果与上面两个效果配合使用的时候,我们会看到两个视图一直在碰撞,有点永远不会停下来的感觉


你可能感兴趣的:(软件开发类)