UIDynamic

物理引擎UIDynamic简介

  1. 什么是UIDynamic?

    UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架。可以认为是一种物理引擎,能模拟和仿真现实生活中的物理现象,重力、弹性碰撞等现象

  2. 物理引擎的价值

    广泛用于游戏开发,经典成功案例是“愤怒的小鸟”。让开发人员可以在远离物理学公式的情况下,实现炫酷的物理仿真效果。提高了游戏开发效率,产生更多优秀好玩的物理仿真游戏

  3. 使用步骤

    1. 创建一个物理仿真器(顺便设置仿真范围)
    2. 创建相应的物理仿真行为(顺便添加物理仿真元素)
    3. 将物理仿真行为添加到物理仿真器中 开始仿真

三大概念

物理仿真元素(Dynamic Item)

不是任何对象都能做物理仿真元素
不是任何对象都能进行物理仿真

哪些对象才能做物理仿真元素

任何遵守了UIDynamicItem协议的对象
UIView默认已经遵守了UIDynamicItem协议,因此任何UI控件都能做物理仿真
UICollectionViewLayoutAttributes类默认也遵守UIDynamicItem协议

物理仿真行为(Dynamic Behavior)

执行怎样的物理仿真效果?怎样的动画效果?
UIDynamic提供了以下几种物理仿真行为

UIGravityBehavior:重力行为
UICollisionBehavior:碰撞行为
UISnapBehavior:捕捉行为
UIPushBehavior:推动行为

物理仿真行为须知

上述所有物理仿真行为都继承自UIDynamicBehavior
所有的UIDynamicBehavior都可以独立进行
组合使用多种行为时,可以实现一些比较复杂的效果

物理仿真器(Dynamic Animator)

让物理仿真元素执行具体的物理仿真行为

物理仿真器须知

它可以让物理仿真元素执行物理仿真行为
它是UIDynamicAnimator类型的对象

UIDynamicAnimator的初始化

- (instancetype)initWithReferenceView:(UIView *)view;
view参数:是一个参照视图,表示物理仿真的范围

UIDynamicAnimator的常见方法

添加1个物理仿真行为
    - (void)addBehavior:(UIDynamicBehavior *)behavior;
移除1个物理仿真行为
    - (void)removeBehavior:(UIDynamicBehavior *)behavior;
移除之前添加过的所有物理仿真行为
    - (void)removeAllBehaviors;

UIDynamicAnimator的常见属性

参照视图
    @property (nonatomic, readonly) UIView* referenceView;
添加到物理仿真器中的所有物理仿真行为
    @property (nonatomic, readonly, copy) NSArray* behaviors;
是否正在进行物理仿真
    @property (nonatomic, readonly, getter = isRunning) BOOL running;
代理对象(能监听物理仿真器的仿真过程,比如开始和结束)
    @property (nonatomic, assign) id <UIDynamicAnimatorDelegate> delegate;

常用行为演练

使用技巧:根据仿真元素创建仿真行为, 添加到仿真器即可执行该行为

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var box1: UIImageView!
    @IBOutlet weak var box2: UIImageView!

    lazy var animator: UIDynamicAnimator = {
        return UIDynamicAnimator(referenceView: self.view)
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        view.backgroundColor = UIColor(patternImage: UIImage(named: "background")!)

    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        let point = touches.first?.location(in: view)
        snap(point: point!)

        push()
        gravity()
        collision()
    }

    //重力行为(UIGravityAnimator)
    //给定重力方向、加速度,让物体朝着重力方向掉落
    func gravity() {

        let behavior = UIGravityBehavior(items: [box1,box2])

        animator.addBehavior(behavior)
    }

    //碰撞行为(UICollisionBehavior)
    //可以让物体之间实现碰撞效果
    //可以通过添加边界(boundary),让物理碰撞局限在某个空间中
    func collision() {
        let behavior = UICollisionBehavior(items: [box1,box2])

        //边界碰撞
        behavior.translatesReferenceBoundsIntoBoundary = true

        /*
         设置碰撞模式
         public static var items: UICollisionBehaviorMode { get } //只碰撞元素
         public static var boundaries: UICollisionBehaviorMode { get } //只碰撞边界
         public static var everything: UICollisionBehaviorMode { get } //可以碰撞任何东西
         */
        behavior.collisionMode = UICollisionBehaviorMode.everything

        //设置内边距
        behavior.setTranslatesReferenceBoundsIntoBoundary(with: UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))

        let startPoint = CGPoint(x:5,y:UIScreen.main.bounds.height * 0.5 + 200)
        let endPoint = CGPoint(x: view.bounds.width - 5, y: view.bounds.height - 5)
        behavior.addBoundary(withIdentifier: "line" as NSCopying, from: startPoint, to: endPoint)

        //设置碰撞代理,监听碰撞情况
        behavior.collisionDelegate = self


        animator.addBehavior(behavior)
    }

    //捕捉行为(UISnapBehavior)
    //可以让物体迅速冲到某个位置(捕捉位置),捕捉到位置之后会带有一定的震动
    func snap(point:CGPoint) {

        //如果想要多次执行捕捉行为,必须移除之前添加的捕捉行为
        animator.removeAllBehaviors()

        let behavior = UISnapBehavior(item: box2, snapTo: point)

        animator.addBehavior(behavior)
    }

    //推动行为 (UIPushBehavior)
    //可以向某个方向, 推动某个物体
    func push() {
        let behavior = UIPushBehavior(items: [box1,box2], mode: .instantaneous)

        //设置推动的方向
        behavior.pushDirection = CGVector(dx: 0, dy: -6)

        animator.addBehavior(behavior)
    }

}

extension ViewController : UICollisionBehaviorDelegate {

    func collisionBehavior(_ behavior: UICollisionBehavior, beganContactFor item1: UIDynamicItem, with item2: UIDynamicItem, at p: CGPoint) {
        print("开始碰撞,元素-元素")
    }

    func  collisionBehavior(_ behavior: UICollisionBehavior, beganContactFor item: UIDynamicItem, withBoundaryIdentifier identifier: NSCopying?, at p: CGPoint) {
        print("开始碰撞,元素-边界")
    }

    func collisionBehavior(_ behavior: UICollisionBehavior, endedContactFor item1: UIDynamicItem, with item2: UIDynamicItem) {
        print("结束碰撞,元素-元素")
    }

    func collisionBehavior(_ behavior: UICollisionBehavior, endedContactFor item: UIDynamicItem, withBoundaryIdentifier identifier: NSCopying?) {
        print("结束碰撞,元素-边界")
    }
}

results matching ""

    No results matching ""