UIDynamic

作者: Carson_Zhu | 来源:发表于2018-02-09 23:08 被阅读15次

    简介

    UIDynamiciOS 7之后新添加的一些物理仿真动画库,包含在UIKit框架中。

    UIDynamic中的三个重要概念:
    • UIDynamicAnimator
      动画引擎。为动力学元素提供物理学相关的能力及动画,同时为这些元素提供相关的上下文,是动力学元素与底层iOS物理引擎之间的中介。
    • UIDynamicBehavior
      仿真行为。创建时,需要附带动画将要作用的视图。
    • UIDynamicItem
      动力学元素。从iOS7开始,UIViewUICollectionViewLayoutAttributes默认实现协议,如果自定义对象实现了该协议,即可通过Dynamic Animator实现物理仿真。

    UIDynamicAnimator

    • 创建
      - (instancetype)initWithReferenceView:(UIView *)view;
      
      view参数:是一个参照视图,表示物理仿真的范围。
    • 添加一个物理仿真行为
      - (void)addBehavior:(UIDynamicBehavior *)behavior;
      
    • 移除一个物理仿真行为
      - (void)removeBehavior:(UIDynamicBehavior *)behavior;
      
    • 移除之前添加过的所有物理仿真行为
      - (void)removeAllBehaviors;
      
    • 更新我们已经修改的动态项目
      - (void)updateItemUsingCurrentState:(id <UIDynamicItem>)item;
      
    • 参照视图
      @property (nonatomic, readonly) UIView* referenceView;
      
    • 添加到物理仿真器中的所有物理仿真行为
      @property (nonatomic, readonly, copy) NSArray* behaviors;
      
    • 是否正在进行物理仿真
      @property (nonatomic, readonly, getter = isRunning) BOOL running;
      
    • 代理对象(能监听物理仿真器的仿真过程,比如开始和结束)
      @property (nonatomic, assign) id <UIDynamicAnimatorDelegate> delegate;
      
      @optional
      // 当dynamicAnimator将要恢复调用
      -(void)dynamicAnimatorWillResume:(UIDynamicAnimator *)animator;
      // 当dynamicAnimator已经暂停调用
      -(void)dynamicAnimatorDidPause:(UIDynamicAnimator *)animator;
      

    UIDynamicItem

    • 中心
      @property (nonatomic, readwrite) CGPoint center;
      
    • 实时范围
      @property (nonatomic, readonly) CGRect bounds;
      
    • 旋转状态
      @property (nonatomic, readwrite) CGAffineTransform transform;
      

    UIDynamicBehavior

    在通常情况下我们不会直接使用UIDynamicBehavior类,而是使用它的子类们。在开始介绍它的子类前,先来看看UIDynamicBehavior作为父类的一些属性和方法:

    • 添加一个自定义行为子类
      - (void)addChildBehavior:(UIDynamicBehavior *)behavior;
      
    • 移除一个自定义行为子类
      - (void)removeChildBehavior:(UIDynamicBehavior *)behavior;
      
    • 当一个动态行为被添加或移除,会回调该函数
      - (void)willMoveToAnimator:(nullable UIDynamicAnimator *)dynamicAnimator;
      
    • 子行为 (只读)
      @property (nonatomic, readonly, copy) NSArray<__kindof UIDynamicBehavior *> *childBehaviors;
      
    • 在运行时调用的每一个动画步骤的block形式动作代码
      @property (nullable, nonatomic,copy) void (^action)(void);
      
    • 所属的dynamicAnimator
      @property (nullable, nonatomic, readonly) UIDynamicAnimator *dynamicAnimator;
      
    1. UIGravityBehavior(重力行为)
    • 构造
      // 根据动力元素组构造
      - (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items;
      
      // 添加动力元素
      - (void)addItem:(id <UIDynamicItem>)item;
      // 删除动力元素
      - (void)removeItem:(id <UIDynamicItem>)item;
      // 获取说有动力元素
      @property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;
      
    • 重力方向
      // 这是二维坐标系中的方向,默认是(0.0, 1.0),表示垂直向下,数值越大;数值可以为负,如(0.0, -1.0)就表示重力方向是垂直向上。也可以利用x和y来表示二维坐标系中的任意方向。例如(1.0, 1.0)沿右下角45度方向,(1.0, 100000)极度接近竖直向下方向。
      @property (readwrite, nonatomic) CGVector gravityDirection;
      
    • 重力角度
      // 是一个角度,x轴正方向为0°,顺时针正数,逆时针负数)。
      @property (readwrite, nonatomic) CGFloat angle;
      
    • 力的系数
      // 正数时,沿`gravityDirection`方向,数值越大,加速度越大;负数时,`gravityDirection`的反方向,数值越小,加速度越大。
      @property (readwrite, nonatomic) CGFloat magnitude;
      

    实例

    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    gravity.gravityDirection = CGVectorMake(0, 1);
    //gravity.angle = M_PI*0.01;    
    [self.animator addBehavior:gravity];
    
    效果:
    2. UICollisionBehavior (碰撞行为)
    • 构造
      // 根据动力元素组构造
      - (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items
      
      // 添加动力元素
      - (void)addItem:(id <UIDynamicItem>)item;
      // 删除动力元素
      - (void)removeItem:(id <UIDynamicItem>)item;
      // 获取所有动力元素
      @property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;
      
    • 碰撞模式
      @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode;
      
      typedef NS_OPTIONS(NSUInteger, UICollisionBehaviorMode) {
        UICollisionBehaviorModeItems        = 1 << 0, 元素碰撞
        UICollisionBehaviorModeBoundaries   = 1 << 1, 边界碰撞
        UICollisionBehaviorModeEverything   = NSUIntegerMax 全体碰撞
      } NS_ENUM_AVAILABLE_IOS(7_0);
      
    • 碰撞边界
      // 是否检测碰撞的边界
      @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary;
      // 设置碰撞`ReferenceView`边界的内边距
      - (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets;
      
      // 通过添加贝塞尔曲线,添加碰撞边界
      - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath *)bezierPath;
      // 通过添加由两点组成的线段,添加碰撞边界
      - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2;
      
      // 根据获取指定已命名的碰撞边界的贝塞尔曲线
      - (nullable UIBezierPath *)boundaryWithIdentifier:(id <NSCopying>)identifier;
      // 移除指定已命名的碰撞边界
      - (void)removeBoundaryWithIdentifier:(id <NSCopying>)identifier;
      // 获得所有命名
      @property (nullable, nonatomic, readonly, copy) NSArray<id <NSCopying>> *boundaryIdentifiers;
      // 移除所有添加的碰撞边界
      - (void)removeAllBoundaries;
      
    • 代理
      // 碰撞代理
      @property (nullable, nonatomic, weak, readwrite) id <UICollisionBehaviorDelegate> collisionDelegate;
      
      @optional
      // 当一个两个动态元素之间发生碰撞时调用
      - (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:(nullable id <NSCopying>)identifier atPoint:(CGPoint)p;
      // 当一个动态元素与边界碰撞结束时调用
      - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(nullable id <NSCopying>)identifier;
      

    实例一: 元素之间的碰撞

    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    gravity.gravityDirection = CGVectorMake(1, 1);
    [self.animator addBehavior:gravity];
        
    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.redView, self.blueView]];
    collision.collisionMode = UICollisionBehaviorModeItems;
    collision.translatesReferenceBoundsIntoBoundary = YES;
    [self.animator addBehavior:collision];
    
    效果:

    实例二: 边界碰撞

    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    gravity.gravityDirection = CGVectorMake(1, 1);
    [self.animator addBehavior:gravity];
        
    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.redView, self.blueView]];
    collision.collisionMode = UICollisionBehaviorModeBoundaries;
    collision.translatesReferenceBoundsIntoBoundary = YES;
    [self.animator addBehavior:collision];
    
    效果:

    实例三: 碰撞所有

    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    gravity.gravityDirection = CGVectorMake(1, 1);
    [self.animator addBehavior:gravity];
        
    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.redView, self.blueView]];
    collision.collisionMode = UICollisionBehaviorModeEverything;
    collision.translatesReferenceBoundsIntoBoundary = YES;
    [self.animator addBehavior:collision];
    
    效果:

    实例四: 碰撞边界内边距

    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    gravity.gravityDirection = CGVectorMake(1, 1);
    [self.animator addBehavior:gravity];
        
    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.redView, self.blueView]];
    collision.collisionMode = UICollisionBehaviorModeEverything;
    [collision setTranslatesReferenceBoundsIntoBoundaryWithInsets:UIEdgeInsetsMake(50, 50, 50, 50)];
    // 检测边距和内边距互相冲突,以最后设置为准
    // collision.translatesReferenceBoundsIntoBoundary = NO;
    [self.animator addBehavior:collision];
    
    效果:

    实例五: 贝塞尔曲线边界

    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    gravity.gravityDirection = CGVectorMake(1, 1);
    [self.animator addBehavior:gravity];
        
    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.redView]];
    collision.collisionMode = UICollisionBehaviorModeEverything;
        
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 70, 200, 400)];
    [collision addBoundaryWithIdentifier:@"path" forPath:path];
    [self.animator addBehavior:collision];
    
    效果:

    实例六: 两点组成的线段边界

    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    gravity.gravityDirection = CGVectorMake(1, 1);
    [self.animator addBehavior:gravity];
        
    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.redView]];
    collision.collisionMode = UICollisionBehaviorModeEverything;
        
    [collision addBoundaryWithIdentifier:@"line" fromPoint:CGPointMake(200, 100) toPoint:CGPointMake(50, 400)];
    [self.animator addBehavior:collision];
    
    效果:
    3. UIAttachmentBehavior (附着行为)

    附着行为一般都是添加手势,让视图跟着手势移动,因为一般都是与手势搭配使用。

    • 构造
      // 元素和锚点之间的吸附
      - (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point;
      // 元素和锚点之间的吸附,offset参数设置元素吸附力作用点的偏移量
      - (instancetype)initWithItem:(id <UIDynamicItem>)item offsetFromCenter:(UIOffset)offset attachedToAnchor:(CGPoint)point NS_DESIGNATED_INITIALIZER;
      
      // 元素和元素之间的吸附 
      - (instancetype)initWithItem:(id <UIDynamicItem>)item1 attachedToItem:(id <UIDynamicItem>)item2;
      // 元素和元素之间的吸附,offset1、offset2分别是两个元素吸附力作用点的偏移量
      - (instancetype)initWithItem:(id <UIDynamicItem>)item1 offsetFromCenter:(UIOffset)offset1 attachedToItem:(id <UIDynamicItem>)item2 offsetFromCenter:(UIOffset)offset2 NS_DESIGNATED_INITIALIZER;
      
    • 锚点
      当吸附发生在元素和锚点之间的时候,我们可以通过anchorPoint属性获得锚点位置,如果吸附发生在元素和元素之间的时候,该属性的值为(0, 0)。
      @property (readwrite, nonatomic) CGPoint anchorPoint;
      
    • 元素吸附力作用点和锚点的距离
      @property (readwrite, nonatomic) CGFloat length;
      
    • 振动频率
      除了刚性吸附之外弹性吸附也是很常用的类型,frequency属性就对弹性吸附有着直接的影响。
      // 值越大,弹性运动的频率越快。
      @property (readwrite, nonatomic) CGFloat frequency;
      
    • 弹性阻力
      属性是设置元素在弹性吸附时震动所受到的阻力,值越大,阻力越大,弹性运动震动的幅度越小。
      @property (readwrite, nonatomic) CGFloat damping;
      
    • 旋转阻力
      旋转力矩,指围绕一点旋转所受的阻力,默认值0.0,值越大,阻力越大。
      @property (readwrite, nonatomic) CGFloat frictionTorque NS_AVAILABLE_IOS(9_0);
      
    • 运动范围
      @property (readwrite, nonatomic) UIFloatRange attachmentRange NS_AVAILABLE_IOS(9_0);
      

    实例一: 元素和锚点

    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    gravity.gravityDirection = CGVectorMake(1.0f, 1.0f);
    [self.animator addBehavior:gravity];
        
    UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:self.redView attachedToAnchor:CGPointMake(200, 300)];
    attachment.length = 50;
    [self.animator addBehavior:attachment];
    
    效果:

    实例二: 元素和锚点加偏移

    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    gravity.gravityDirection = CGVectorMake(1.0f, 1.0f);
    [self.animator addBehavior:gravity];
        
    UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:self.redView offsetFromCenter:UIOffsetMake(25, 0) attachedToAnchor:CGPointMake(200, 300)];
    attachment.length = 50;
    [self.animator addBehavior:attachment];
    
    效果:

    实例三: 元素与元素

    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    gravity.gravityDirection = CGVectorMake(0, 1.0f);
    [self.animator addBehavior:gravity];
        
    UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:self.redView attachedToItem:self.blueView];
    attachment.length = 100;
    [self.animator addBehavior:attachment];
    
    效果:

    实例四: 手势依附

    // 添加手势
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] init];
    [pan addTarget:self action:@selector(panDidHandler:)];
    [self.view addGestureRecognizer:pan];
    
    // 手势响应
    - (void)panDidHandler:(UIPanGestureRecognizer *)pan {
        CGPoint location = [pan locationInView:self.view];
        if (pan.state == UIGestureRecognizerStateBegan) {
            self.attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:self.redView attachedToAnchor:location];
            [self.animator addBehavior:self.attachmentBehavior];
        } else if (pan.state == UIGestureRecognizerStateChanged) {
            self.attachmentBehavior.anchorPoint = location;
        } else if (pan.state == UIGestureRecognizerStateEnded) {
            [self.animator removeBehavior:self.attachmentBehavior];
        }
    }
    
    效果:
    4. UIPushBehavior(推动行为)
    • 构造
      // 根据动力元素组和推动类型构造
      - (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items mode:(UIPushBehaviorMode)mode NS_DESIGNATED_INITIALIZER;
      
      typedef NS_ENUM(NSInteger, UIPushBehaviorMode) {
          UIPushBehaviorModeContinuous, // 连续的推动
          UIPushBehaviorModeInstantaneous // 瞬间的推动
      } NS_ENUM_AVAILABLE_IOS(7_0);
      
      // 添加动力元素
      - (void)addItem:(id <UIDynamicItem>)item;
      // 删除动力元素
      - (void)removeItem:(id <UIDynamicItem>)item;
      // 获取所有动力元素
      @property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;
      
    • 作用力中心偏移量
      - (UIOffset)targetOffsetFromCenterForItem:(id <UIDynamicItem>)item;
      - (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item;
      
    • 设置推力
      // 推力方向
      @property (readwrite, nonatomic) CGVector pushDirection;
      // 推力角度
      @property (readwrite, nonatomic) CGFloat angle;
      // 推力矢量的大小
      @property (readwrite, nonatomic) CGFloat magnitude;
      // 设置推力的角度和推力矢量的大小
      -(void)setAngle:(CGFloat)angle magnitude:(CGFloat)magnitude;
      
    • 推动行为是否处于活跃状态
      在添加一个pushBehavioranimator时,使用这个属性来激活或禁用推力作用,而不是通过重新添加behavior来实现。
      @property (nonatomic, readwrite) BOOL active;
      

    实例一: 瞬间推动UIPushBehaviorModeInstantaneous

    UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[self.redView] mode:UIPushBehaviorModeInstantaneous];
    pushBehavior.pushDirection = CGVectorMake(0.5, 0.5);
    [self.animator addBehavior:pushBehavior];
        
    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.redView]];
    collision.collisionMode = UICollisionBehaviorModeEverything;
    collision.translatesReferenceBoundsIntoBoundary = YES;
    [self.animator addBehavior:collision];
    

    效果:


    实例二: 连续推动UIPushBehaviorModeContinuous
    UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[self.redView] mode:UIPushBehaviorModeContinuous];
    pushBehavior.pushDirection = CGVectorMake(0.5, 0.5);
    [self.animator addBehavior:pushBehavior];
        
    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.redView]];
    collision.collisionMode = UICollisionBehaviorModeEverything;
    collision.translatesReferenceBoundsIntoBoundary = YES;
    [self.animator addBehavior:collision];
    
    效果:

    实例三: 作用力中心偏移

    UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[self.redView] mode:UIPushBehaviorModeInstantaneous];
    pushBehavior.pushDirection = CGVectorMake(0.5, 0.5);
    [pushBehavior setTargetOffsetFromCenter:UIOffsetMake(-25, 0) forItem:self.redView];
    [self.animator addBehavior:pushBehavior];
        
    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.redView]];
    collision.collisionMode = UICollisionBehaviorModeEverything;
    collision.translatesReferenceBoundsIntoBoundary = YES;
    [self.animator addBehavior:collision];
    
    效果:
    5. UIDynamicItemBehavior (动力行为)

    因为可以设置摩擦力、弹力、密度、阻力等参数,在模拟视图运动的能量损失。

    • 构造
      // 根据动力元素组构造
      - (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items NS_DESIGNATED_INITIALIZER;
      
      // 添加动力元素
      - (void)addItem:(id <UIDynamicItem>)item;
      // 删除动力元素
      - (void)removeItem:(id <UIDynamicItem>)item;
      // 获取所有动力元素
      @property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;
      
    • 弹性系数
      用于碰撞行为的动态元素的弹性量。默认0,范围0.0 ~ 1.0。
      @property (readwrite, nonatomic) CGFloat elasticity;
      
    • 摩擦系数
      用于两个发生摩擦的动态元素。默认值0.0(没有摩擦),当值为1.0时,强烈摩擦。如果设置更高的摩擦,可以使用更高的数值。
      @property (readwrite, nonatomic) CGFloat friction;
      
    • 相对质量密度
      用于动态元素相对密度。其连同动态元素大小,决定动态元素的有效质量。其参与的动力学行为包括摩擦、碰撞、推动等...默认1。
      @property (readwrite, nonatomic) CGFloat density;
      

      假设你有两个具有相同密度但大小不同的动态元素:元素一尺寸为100x100像素点,元素二尺寸为100x200像素点。
      这个例子中,元素二的有效质量是元素一的两倍。
      在一个弹性碰撞中,这些元素根据它们的相对质量表现出自然的动量守恒。元素一密度为1.0,当施加一个力(通过推动行为)1.0级时,加速度为100点/s²。

    • 线速度阻尼
      默认值是0.0。有效范围从0.0(没有速度阻尼)到CGFLOAT_MAX(最大速度阻尼)。当设置为1.0,动态元素会立马停止就像没有力量作用于它一样。
      @property (readwrite, nonatomic) CGFloat resistance;
      
    • 角速度阻尼
      有效范围从0.0到CGFLOAT_MAX,值越大,角速度阻尼越大,旋转减速越快,到停止。
      @property (readwrite, nonatomic) CGFloat angularResistance;
      
    • 电荷
      电荷数确定动态元素与电场和磁场相互作用的程度。这个属性值没有单位,电磁场强度由你调控的适当的值来决定。默认值0.0。
      @property (readwrite, nonatomic) CGFloat charge NS_AVAILABLE_IOS(9_0);
      
    • 是否固定
      当一个动态元素被设置为固定后,该元素参与碰撞,但不受碰撞影响,仿佛成为一个碰撞边界。默认值为NO。
      @property (nonatomic, getter = isAnchored) BOOL anchored NS_AVAILABLE_IOS(9_0);
      
    • 添加一个动态元素,并设置它的角速度
      默认值为0.0,单位弧度/秒。设置一个负值,减少一定角速度。
      -(void)addAngularVelocity:(CGFloat)velocity forItem:(id<UIDynamicItem>)item;
      
    • 添加一个动态元素,并设置它的线速度
      默认值为0.0,单位点/秒。设置一个负值,减少一定线速度。
      -(void)addLinearVelocity:(CGPoint)velocity forItem:(id<UIDynamicItem>)item;
      
    • 获得动态元素的角速度
      -(CGFloat)angularVelocityForItem:(id<UIDynamicItem>)item;
      
    • 获得动态元素的线速度
      -(CGPoint)linearVelocityForItem:(id<UIDynamicItem>)item;
      

    实例:

    - (void)addDynamicItem {
        UIDynamicItemBehavior *dynamicItem = [[UIDynamicItemBehavior alloc] initWithItems:@[self.redView]];
        dynamicItem.elasticity = 0.5f; // 弹性系数
        dynamicItem.friction = 1.0f; // 摩擦系数
        dynamicItem.density = 10.0f; // 相对质量密度
        dynamicItem.resistance = 10.0f; // 线性阻尼
        dynamicItem.angularResistance = 10.0f; // 角度阻尼
        [self.animator addBehavior:dynamicItem];
        
        // 推动行为
        UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[self.redView] mode:UIPushBehaviorModeInstantaneous];
        pushBehavior.pushDirection = CGVectorMake(0.5, 0);
        pushBehavior.magnitude = 20;
        [pushBehavior setTargetOffsetFromCenter:UIOffsetMake(0, -25) forItem:self.redView];
        [self.animator addBehavior:pushBehavior];
        
        // 碰撞行为
        UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[self.redView]];
        collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
        [self.animator addBehavior:collisionBehavior];
    }
    
    效果:
    6. UISnapBehavior (捕获行为)

    捕获行为是定义一个动态元素运动到指定点,运动过程伴随弹簧效果。

    • 构造
      - (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point NS_DESIGNATED_INITIALIZER;
      
    • 捕获点
      该属性的默认值为initWithItem:snapToPoint:方法设置的值,当该属性的值发生改变时,捕获行为会更新,动态元素会向新的捕获点捕获。
      @property (nonatomic, assign) CGPoint snapPoint NS_AVAILABLE_IOS(9_0);
      
    • 震动阻尼
      阻尼的有效范围为0.0~1.0,0.0最大震荡、1.0最小震荡,默认值为0.5。
      @property (nonatomic, assign) CGFloat damping;
      

    实例:

    UISnapBehavior *snapBehavior = [[UISnapBehavior alloc] initWithItem:self.redView snapToPoint:CGPointMake(200, 300)];
    snapBehavior.damping = 0.2f;
    [self.animator addBehavior:snapBehavior];
    
    效果:

    相关文章

      网友评论

          本文标题:UIDynamic

          本文链接:https://www.haomeiwen.com/subject/jmaxtftx.html