美文网首页
12.UIKit动力学

12.UIKit动力学

作者: LucXion | 来源:发表于2021-12-01 09:47 被阅读0次

    UIKit动力学三大要素

    • 动力项,要做动画的元素。最常见的是视图,但任何遵从UIDynamicItem协议的动力项都可以,该协议包括bounds、center、transform属性。
    • 行为,伴随时间影响一个或多个动力项。包括动力项附着到一点,重力、摩擦力。
    • 动画类,伴随时间对动力项实施行为的引擎。

    动力项附加到行为,行为附加到动画类。动力项不知道它的行为,如果一个视图添加了重力行为,接着将视图移除出父视图,则动力项会持续持有该视图,并对其进行动画,即使视图不可见。

    内置行为

    iOS 内置了可以处理大多数简单需求的有用的行为,包括迅速移动、附着、重力、碰撞、推力和动力项。

    • 迅速移动 UISnapBehavior

      锚点设置为视图的中心点,视图就拥有可旋转的效果

      @property (nonatomic) UIDynamicAnimator *dynamicAnimator;
      // 根据参考视图初始化动力学动画类
      self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
      // 通过initWithCollectionViewLayout 的方式来对集合视图进行动画,这种方式创建出来的动画类对UICollectionViewLayoutAttributes 对象进行动画
      // 通过init 方式创建出来的动画类,没有参考视图,可以对任意遵从<UIDynamicItem>对象进行动画
      
      // 移除所有行为
      - (IBAction)reset {
        [self.dynamicAnimator removeAllBehaviors];
      }
      
      // 迅速移动 = 位移 + 弹力效果
      - (IBAction)snap {
        CGPoint point = [self randomPoint];
        UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:self.box
                                                        snapToPoint:point];
        // 位移修改属性,默认值0.5,越高越慢
        snap.damping = 0.25;
          
       [self.dynamicAnimator addBehavior:snap];
       [self.dynamicAnimator performSelector:@selector(removeBehavior:)
                                     withObject:snap
                                     afterDelay:1];
      }
      
    • 附着 UIAttachmentBehavior

      如果在一个动力项上添加多个行为,比如附着 + 迅速移动,那么会导致项目更加抖动且围绕附着点旋转,解决办法是使用多个附着

      - (IBAction)attach {
          // 可以附着到一个点上,并偏移中心
        UIAttachmentBehavior *attach1 = [[UIAttachmentBehavior alloc] initWithItem:self.box1
                                                                 offsetFromCenter:UIOffsetMake(25, 25)
                                                                 attachedToAnchor:self.box1.center];
        [self.dynamicAnimator addBehavior:attach1];
           // 也可以附着到一个项目上
        UIAttachmentBehavior *attach2 = [[UIAttachmentBehavior alloc] initWithItem:self.box2
                                                                   attachedToItem:self.box1];
        [self.dynamicAnimator addBehavior:attach2];
      
      // UIPushBehaviorModeInstantaneous 一个瞬间的推动
        UIPushBehavior *push = [[UIPushBehavior alloc] initWithItems:@[self.box2]
                                                                mode:UIPushBehaviorModeInstantaneous];
        push.pushDirection = CGVectorMake(0, 2);
        [self.dynamicAnimator addBehavior:push];
      }
      
    • 推力 UIPushBehavior

    • 重力 UIGravityBehavior

      一个动力学动画类只能有一个重力行为

      标准的UIKit重力是(0,1),即一个大小的向下向量,它对所有动力项以1000p/s2进行加速

      UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.box1,
                                                                                self.box2]];
        gravity.action = ^{
          NSLog(@"%@", NSStringFromCGPoint(self.box1.center));
        };
        [self.dynamicAnimator addBehavior:gravity];
      
    • 碰撞 UICollisionBehavior

      • 可以通过setTranslatesReferenceBoundsIntoBoundary、setTranslatesReferenceBoundsIntoBoundaryWithInsets给碰撞设置边界
      • 创建碰撞行为后,可以添加、删除对象,也可以添加或删除边界,边界通过标识符跟踪,方便查找修改
      • 碰撞行为还需要一个委托,对象碰撞时可以跟踪,通常用于播放声音,也可以用来添加、删除行为,例如添加一个附着行为,碰撞后就会粘在一起
      UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.box1,
                                                                                      self.box2]];
        [self.dynamicAnimator addBehavior:collision];
      
        UIPushBehavior *push = [[UIPushBehavior alloc] initWithItems:@[self.box1]
                                                                mode:UIPushBehaviorModeInstantaneous];
        push.pushDirection = CGVectorMake(3, 0);
        [self addTemporaryBehavior:push];
      

    动力项

    • UIDynamicItemBehavior 与其他行为不同,用于对动力项赋值物理属性。例如:密度、弹性、摩擦力、阻力。

    • 对一个对象施加推力,移除推力行为,动力项立即停止移动

    • 如果动力项拥有一个动力项行为,即使移除推力行为,动力项也会保持当前速度继续移动。

    实战代码

    行为合集:行为内包含多个内置行为

    // 1. 继承关系 
    @interface DefaultBehavior : UIDynamicBehavior
    // 2. 将需要集合的行为附加到当前行为
      - (instancetype)init {
      self = [super init];
      if (self) {
          // 碰撞行为
        UICollisionBehavior *collisionBehavior = [UICollisionBehavior new];
        collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
        [self addChildBehavior:collisionBehavior];
    
          // 重力行为
        UIGravityBehavior *gravityBehavior = [UIGravityBehavior new];
        [self addChildBehavior:gravityBehavior];
      }
      return self;
    }
    // 3.封装两个对外函数,使动力项可以附加到行为上
    - (void)addItem:(id<UIDynamicItem>)item {
      for (id behavior in self.childBehaviors) {
        [behavior addItem:item];
      }
    }
    - (void)removeItem:(id<UIDynamicItem>)item {
      for (id behavior in self.childBehaviors) {
        [behavior removeItem:item];
      }
    }
      
    

    自定义行为

    // 移动视图  DraggableView
    // 1. 保存控制器动画类 UIDynamicAnimator,添加拖拽手势
    // 2. 实现 <NSCopying> ,传递动画类,同步bounds、center、transform、alpha
    // 3. 响应手势函数:
    //    3.1 拖拽过程中:动画类移除移动行为 UISnapBehavior,通过创建新的移动行为来实现位移 
    //    3.2 拖拽结束:移除移动行为
    
    // 自定义“分裂”行为  TearOffBehavior
    // 1. 初始化
    //    1.1 通过添加 快速移动行为 UISnapBehavior 实现视图可旋转
    [self addChildBehavior:[[UISnapBehavior alloc] initWithItem:view
                                                        snapToPoint:anchor]];
    //    1.2 实现 self.action 属性
              // 1.2.1 当视图发生偏移足够距离,通过复制当前视图,创建一个“分裂”出来的新视图,并将 新视图 附加到 新的分裂 行为上。
              // 1.2.2 注意: handler实际上只有一个,都是原始视图初始化的时候传递的
              // 1.2.3 行为和动画类的交替,移除动画类上前一个分裂行为,只保留新的
              // 1.2.4 给分裂出来的复制品添加碰撞和重力行为,并且添加个移除的特效(通过UIGraphicsBeginImageContext打开上下文将视图切片,通过拼接切片的方式维持原视图的视觉效果,通过施加推力行为+UIView动画使透明度渐变为0,并在动画结束后移除视图)
    

    相关文章

      网友评论

          本文标题:12.UIKit动力学

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