UIKit Dynamics — 本质,iOS中的物理交互

作者: IT Sectr 发布日期: 2026-03-01 阅读时间: 8 分钟

UIKit Dynamics — iOS (UIKit) 中的物理动画框架,允许View根据真实物理定律进行交互:重力、碰撞、弹性和引力。本文解释了UIDynamicAnimator的组件、行为(behavior)的类型以及实际应用场景。

要点

  • UIDynamicAnimator — 物理动画引擎,连接行为(behavior)和对象
  • UIGravityBehavior — 带有方向向量和加速度大小的重力模拟
  • UICollisionBehavior — 处理View与reference view边界之间的碰撞
  • UIDynamicItemBehavior — 物理属性配置:弹性、密度、摩擦力
  • UIAttachmentBehavior — 两点之间具有弹簧或缆绳效果的连接

什么是UIKit Dynamics?

UIKit Dynamics — 由Apple在iOS 7(2013)中引入的物理建模框架。与UIView.animate(线性过渡)和Core Animation(图层动画)不同,UIKit Dynamics模拟真实的物理交互:重力、碰撞、力、弹性和摩擦力。开发者将行为(behaviors)添加到UIDynamicAnimator,系统自动为每一帧计算物理效果。

该框架以60/120 FPS运行,并使用基于刚体模拟(rigid body simulation)的内置物理引擎。UIKit Dynamics不需要物理或数学知识——只需应用现成的行为并配置参数即可。

根据Apple的说法,UIKit Dynamics适用于UI效果(卡堆动画、图标「抖动」、界面物理),但不适用于游戏——游戏请使用SceneKit或SpriteKit。

UIDynamicAnimator — 物理引擎

UIDynamicAnimator — UIKit Dynamics的核心类。它使用reference view(通常是控制器的view)初始化,并管理所有活跃的行为。每一帧,UIDynamicAnimator根据物理定律重新计算所有添加元素的位置、速度和加速度。

addBehavior方法添加一个行为(或复杂的UIDynamicBehavior),removeBehavior — 移除。当所有对象达到静止状态(没有碰撞和力)时,animator自动暂停。委托方法 — UIDynamicAnimatorDelegate — 通知模拟的暂停和恢复。

UIDynamicItem — 动画协议

每个参与物理的对象必须实现UIDynamicItem协议。UIView和UICollectionViewLayoutAttributes已经实现了它。该协议要求属性:bounds、center、transform。如果对象是自定义的,请手动实现该协议。

Dynamic Behaviors的类型

UIKit Dynamics包含七种内置行为类型,每种模拟特定的物理效果。行为可以组合:例如,重力+碰撞+弹性可以产生物体下落和弹跳的效果。

Behavior物理效果关键参数
UIGravityBehavior重力(力矢量)gravityDirection (dx, dy), magnitude
UICollisionBehavior对象和边界的碰撞collisionMode, translucence, collisionDelegate
UIAttachmentBehavior连接(弹簧/缆绳)anchorPoint, length, damping, frequency
UISnapBehavior带阻尼吸引到点snapPoint, damping (0-1)
UIPushBehavior推/冲量(连续或瞬时)pushDirection, magnitude, mode
UIDynamicItemBehavior对象的物理属性elasticity, friction, density, resistance
UIFieldBehavior力场(漩涡、磁铁、半径)position, strength, falloff, region

组合行为

要实现对象的真实物理效果,需要同时使用多种行为。例如,对于下落卡牌:UIGravityBehavior(重力)、UICollisionBehavior(与底部碰撞)、UIDynamicItemBehavior(elasticity: 0.4用于弹跳)。所有行为都添加到同一个UIDynamicAnimator。

Swift代码示例

用于UIKit Dynamics的Swift代码创建UIDynamicAnimator并添加行为。下面的示例演示了具有多个对象、碰撞和自定义物理属性的重力效果。

swift
import UIKit

class PhysicsViewController: UIViewController {

    var animator: UIDynamicAnimator!

    override func viewDidLoad() {
        super.viewDidLoad()

        // 1. 使用reference view创建动画器
        animator = UIDynamicAnimator(referenceView: view)

        // 2. 创建下落对象
        let redView = UIView(frame: CGRect(x: 100, y: 50, width: 60, height: 60))
        redView.backgroundColor = .systemRed
        redView.layer.cornerRadius = 8
        view.addSubview(redView)

        let blueView = UIView(frame: CGRect(x: 200, y: 30, width: 60, height: 60))
        blueView.backgroundColor = .systemBlue
        blueView.layer.cornerRadius = 8
        view.addSubview(blueView)

        // 3. 重力
        let gravity = UIGravityBehavior(items: [redView, blueView])
        gravity.gravityDirection = CGVector(dx: 0, dy: 1)
        gravity.magnitude = 0.8
        animator.addBehavior(gravity)

        // 4. 碰撞
        let collision = UICollisionBehavior(items: [redView, blueView])
        collision.translatesReferenceBoundsIntoBoundary = true
        collision.collisionDelegate = self
        animator.addBehavior(collision)

        // 5. 物理属性
        let itemBehavior = UIDynamicItemBehavior(items: [redView, blueView])
        itemBehavior.elasticity = 0.6
        itemBehavior.friction = 0.3
        itemBehavior.density = 1.0
        animator.addBehavior(itemBehavior)

        // 6. 点击时的Snap行为
        let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        view.addGestureRecognizer(tap)
    }

    @objc
    func handleTap(_ gesture: UITapGestureRecognizer) {
        let point = gesture.location(in: view)

        // 每个对象的Snap行为
        for subview in view.subviews where subview is UIView {
            animator.removeAllBehaviors()
            let snap = UISnapBehavior(item: subview, snapTo: point)
            snap.damping = 0.5
            animator.addBehavior(snap)
        }
    }
}

extension PhysicsViewController: UICollisionBehaviorDelegate {
    func collisionBehavior(_ behavior: UICollisionBehavior,
                             beganContactFor item1: UIDynamicItem,
                             with item2: UIDynamicItem,
                             at point: CGPoint) {
        print("碰撞位置:(point)")
    }
}

该示例创建了两个具有重力、碰撞和物理属性的View。UISnapBehavior在触摸时将对象以0.5的阻尼吸引到触摸点。UICollisionBehaviorDelegate跟踪碰撞的开始以产生声音和视觉效果。

实际应用场景

UIKit Dynamics在iOS应用程序中用于非游戏界面物理效果。常见场景:卡堆动画(UISnapBehavior用于吸引到中心)、错误时屏幕抖动(UIDynamicItemBehavior + UIPushBehavior)、引导页中的「流星」效果(gravity + collision + field behavior)。

为获得最佳性能,UIKit Dynamics建议不超过15-20个同时具有物理效果的对象。每个对象需要在每一帧计算碰撞和力。超过限制时,使用CALayer代替UIView — Core Animation处理图层更高效。

常见问题

UIKit Dynamics与Core Animation有什么区别?

UIKit Dynamics基于刚体模拟建模物理交互(重力、碰撞、力)。Core Animation — 根据给定的时间曲线动画CALayer属性(position、opacity、transform)。Dynamics适用于交互式物理,Core Animation适用于预定义的过渡。

可以在SwiftUI中使用UIKit Dynamics吗?

SwiftUI中没有对UIKit Dynamics的直接支持。对于物理效果,请在UIViewRepresentable中使用UIKitView + UIDynamicAnimator,或通过SwiftUI中的Animation.spring()和withAnimation()使用自定义动画。

如何停止UIKit Dynamics?

调用animator.removeAllBehaviors() — 这将移除所有活跃的物理行为。当所有对象达到静止状态时,animator会自动暂停。对于临时暂停,使用animator.isPaused属性或移除单个行为。

可以同时动画多少个对象?

Apple建议不超过15-20个对象具有完整物理效果(重力+碰撞+力)。对于大规模动画,使用UIFieldBehavior — 它集中计算力而无需成对碰撞,从而减少CPU负载。

总结

  • UIKit Dynamics — iOS物理动画框架,模拟重力、碰撞和力
  • UIDynamicAnimator — 管理行为(behaviors)并在每一帧计算物理效果的引擎
  • 7种行为类型 — UIGravityBehavior, UICollisionBehavior, UIAttachmentBehavior, UISnapBehavior, UIPushBehavior, UIDynamicItemBehavior, UIFieldBehavior
  • 组合 — gravity + collision + itemBehavior创建具有弹跳的真实下落物理效果
  • UIDynamicItem — 参与物理的对象的协议(UIView默认实现)
  • 限制 — 不超过20个具有完整物理效果的对象,不适用于游戏和复杂场景
  • SwiftUI — 使用UIViewRepresentable集成UIKit Dynamics

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读