Swift中的UIKit重力学

前言:
重力学这个名词不论在哪个行业领域听起来似乎都非常高大上。

那么在Swift中的重力学是什么呢?那就是将我们移动端屏幕上毫无生命力的东西也置于万有引力中。使它们能够展现出好像真的因为引力而向下坠落以及碰到物体后自然的弹开的效果。
要想做到这一点,我们得须要两个利器:UIKit Dynamics和Motion Effects。
一、简介
1.UIKit Dynamics是从iOS 7開始引入的一种新技术,隶属于UIKit框架的物理引擎。能模拟和仿真现实生活中的物理现象它能够让我们在程序中对界面元素加入一些行为从而达到诸如重力、弹簧等现实中的动作行为。你仅仅需在引擎中注冊界面元素,并指定好物理行为,其它的事就交给物理引擎去完毕了。


• Motion Effects能够创建非常酷的视差效果。就像你iPhone上横竖屏切换时那样。它基于Apple提供的重力加速器提供的数据计算分析,使我们的界面元素依据移动设备的倾斜方向做出相应的反应。
2.物理引擎的价值
广泛用于游戏开发,经典成功案例是“愤慨的小鸟”
让开发者能够在远离物理学公式的情况下。实现炫酷的物理仿真效果
提高了游戏开发效率,产生很多其它优秀好玩的物理仿真游戏
3.知名的2D物理引擎
Box2d
Chipmunk
二、使用步骤
要想使用UIDynamic来实现物理仿真效果。大致的过程例如以下
(1)创建一个物理仿真器(顺便设置仿真范围)
(2)创建相应的物理仿真行为(顺便加入物理仿真元素)
(3)将物理仿真行为加入到物理仿真器中  開始仿真
三、相关说明
1.三个概念
(1)谁要进行物理仿真?
  物理仿真元素(Dynamic Item)
(2)运行如何的物理仿真效果?如何的动画效果?
  物理仿真行为(Dynamic Behavior)
(3)让物理仿真元素运行详细的物理仿真行为
  物理仿真器(Dynamic Animator)
2.物理仿真元素
注意:不是不论什么对象都能做物理仿真元素
不是不论什么对象都能进行物理仿真
物理仿真元素要素:
不论什么遵守了UIDynamicItem协议的对象
UIView默认已经遵守了UIDynamicItem协议,因此不论什么UI控件都能做物理仿真
UICollectionViewLayoutAttributes类默认也遵守UIDynamicItem协议
3.物理仿真行为
(1)UIDynamic提供了下面几种物理仿真行为
动力行为能够在随意时间内进行加入或移除。

另外动力行为能够是组合的,也能够被继承。能够通过向UIDynamicBehavior或者用户子类化的 UIDynamicBehavior的实例使用addChildBehavior: 方法创建组合行为。(但不能向系统提供的行为使用该方法)
1.吸附行为(UIAttachmentBehavior):有一个对象UIAttachmentBehavior, 该对象用来指定两个动力项(项或点)之间的连接,当一个项或者点移动时,吸附的项也随之移动。当然,这个连接并非全然是静态的(static),吸附的 项有两个属性damping(阻尼)和oscillation(震荡)。这两个属性决定了吸附项的行为是如何随时间而变化的。
(1)UIAttachmentBehavior
指定两个动力项或者动力项和锚点间的连接。动力项默认锚点在他的center。


步骤1.使用initWithItem:方法实例化UIAttachmentBehavior
2.使用addBehavior: 方法将行为加入到动力动画。
能够加入到自己定义的组合行为,假设想在动力动画的每一步改变行为,能够实现继承的 action 方法。

(2)UIAttachmentBehavior实例化方法
convenience init!(item: UIDynamicItem, attachedToAnchor point: CGPoint) //实例化UIAttachmentBehavior,连接dynamic item的center到一个锚点。


convenience init!(item: UIDynamicItem, offsetFromCenter offset: UIOffset, attachedToAnchor point: CGPoint)//实例化UIAttachmentBehavior,连接dynamic item的指定点(相对于dynamic item center的点)到一个锚点。

convenience init!(item item1: UIDynamicItem, attachedToItem item2: UIDynamicItem) //实例化UIAttachmentBehavior,连接dynamic item的center到还有一个dynamic item的center。
init!(item item1: UIDynamicItem, offsetFromCenter offset1: UIOffset, attachedToItem item2: UIDynamicItem, offsetFromCenter offset2: UIOffset)//实例化UIAttachmentBehavior,连接 dynamic item的指定点(相对于dynamic item center的点)到还有一个dynamic item的指定点。

(3)UIAttachmentBehavior经常使用属性:
var items: [AnyObject] { get } //返回行为连接的dynamic items。
var attachedBehaviorType: UIAttachmentBehaviorType { get }//UIAttachmentBehavior的类型。枚举(UIAttachmentBehaviorType.Items,.Anchor)
var anchorPoint: CGPoint // 锚点类型UIAttachmentBehavior的锚点。


var length: CGFloat //两个吸附点间的距离(浮点)
var damping: CGFloat // 1: 阻尼数值(浮点) critical(临界值) damping
var frequency: CGFloat // 震动频率(浮点)in Hertz(单位赫兹)

2.碰撞行为(UICollisionBehavior):通过对象UICollisionBehavior指定一个边界,而且让各个动力项,在该边界内參与碰撞。

UICollisionBehavior对象还能够指定这些动力项适当的回应碰撞。
(1)UICollisionBehavior
指定一些dynamic item能够相互碰撞或者与UICollisionBehavior的界线碰撞。
步骤1.使用init方法创建UICollisionBehavior, 使用addItem: 方法向其加入dynamic item 或者使用initWithItems:实例化UICollisionBehavior。


2. 使用addBehavior: 方法将UICollisionBehavior加入到动力动画

(2)UICollisionBehavior实例化方法及管理:
init!(items: [AnyObject])//使用dynamic item数组实例化UICollisionBehavior
func addItem(item: UIDynamicItem) //向UICollisionBehavior实例加入dynamic item
func removeItem(item: UIDynamicItem)//删除dynamic item
var items: [AnyObject] { get }//返回UICollisionBehavior实例中的dynamic item数组
var collisionMode: UICollisionBehaviorMode //指定碰撞类型
static var Items: UICollisionBehaviorMode { get }
static var Boundaries: UICollisionBehaviorMode { get }
static var Everything: UICollisionBehaviorMode { get }
var translatesReferenceBoundsIntoBoundary: Bool // 基于相对坐标系统的界线是否有效
UICollisionBehavior设置界线的三种方法:
func setTranslatesReferenceBoundsIntoBoundaryWithInsets(insets: UIEdgeInsets)(前提使用reference view 或者 collection view layout实例化的动力动画)注意: dynamic item的初始位置不能在界线外
func addBoundaryWithIdentifier(identifier: NSCopying, forPath bezierPath: UIBezierPath)
func addBoundaryWithIdentifier(identifier: NSCopying, fromPoint p1: CGPoint, toPoint p2: CGPoint)

func boundaryWithIdentifier(identifier: NSCopying) -> UIBezierPath?//返回指定标示符相应的贝塞尔曲线界线
func removeBoundaryWithIdentifier(identifier: NSCopying)//移除指定标示符相应的贝塞尔曲线界线
var boundaryIdentifiers: [AnyObject]? { get }//返回UICollisionBehavior 实例的全部界线标示符
func removeAllBoundaries()
unowned(unsafe) var collisionDelegate: UICollisionBehaviorDelegate? //实例的collisionDelegate会响应 碰撞的一些回调方法

3.重力行为(UIGravityBehavior):通过对象UIGravityBehavior给动力项指定一个重力矢量,具有重力矢量的动力项,会在重力矢量的方向上一直加速。直到与别的动力项产生了冲突或者。遇到了边界。

(1) UIGravityBehavior实例化方法及管理:
init(items: [AnyObject])//使用dynamic item数组实例化UIGravityBehavior
func addItem(item: UIDynamicItem)//向UIGravityBehavior实例加入dynamic item
func removeItem(item: UIDynamicItem)//移除UIGravityBehavior实例的dynamic item
var items: [AnyObject] { get }//返回UIGravityBehavior实例中的dynamic item数组

// The default value for the gravity vector is (0.0, 1.0)
// The acceleration for a dynamic item subject to a (0.0, 1.0) gravity vector is downwards at 1000 points per second².
var gravityDirection: CGVector //航行的方向,趋势(范围是(0.0, 1.0))

var angle: CGFloat// 角度
var magnitude: CGFloat// 速率 angle的值为0时,方块会水平向右移动。随着值的增大,方块会顺时针改变角度。只是我们要模拟现实中的重力。所以该属性一般不设置,不设置时默认是垂直向下移动。magnitude是重力行为的速率属性,值越大下降的速度越快,当magnitude属性的值为0时,方块就不会下降了,所以最小的速率是0.1。

func setAngle(angle: CGFloat, magnitude: CGFloat)//角度和速率一起设置

4.推动行为(UIPushBehavior):通过对象UIPushBehavior给动力项指定一个持续的或者瞬时的力(force vector)。

(1) UIPushBehavior实例化方法及管理:
init!(items: [AnyObject]!, mode: UIPushBehaviorMode)
func addItem(item: UIDynamicItem)
func removeItem(item: UIDynamicItem)
var items: [AnyObject] { get }

func targetOffsetFromCenterForItem(item: UIDynamicItem) -> UIOffset // 偏移
func setTargetOffsetFromCenter(o: UIOffset, forItem item: UIDynamicItem)

var mode: UIPushBehaviorMode { get } // 推送的模式
var active: Bool // 是否活动

var angle: CGFloat // 角度
// A continuous force vector with a magnitude of 1.0, applied to a 100 point x 100 point view whose density value is 1.0, results in view acceleration of 100 points per s^2
var magnitude: CGFloat //速率
var pushDirection: CGVector //推送的航向趋势
func setAngle(angle: CGFloat, magnitude: CGFloat) //设置角度和速率

5.捕捉行为(UISnapBehavior):通过对象UISnapBehavior给动力项指定一个捕捉点。动力项会依据配置的效果,来抓住这一捕捉点。
(1) UISnapBehavior实例化方法及管理
// The point argument is expressed in the reference coordinate system
init!(item: UIDynamicItem, snapToPoint point: CGPoint)

var damping: CGFloat // damping value from 0.0 to 1.0. 0.0 is the least oscillation.

6.动力元素行为(UIDynamicItemBehavior)

(1) UIDynamicItemBehavior
步骤1.使用init方法创建UICollisionBehavior,使用addItem: 方法向其加入dynamic item 或者使用initWithItems:实例化UIDynamicItemBehavior。
2. 使用addBehavior: 方法将UIDynamicItemBehavior加入到动力动画
(2) UIDynamicItemBehavior实例化方法及管理:
init(items: [AnyObject])
func addItem(item: UIDynamicItem)
func removeItem(item: UIDynamicItem)
var items: [AnyObject] { get }

var elasticity: CGFloat // 设置碰撞弹性系数。

范围(0.0-1.0) var friction: CGFloat // 设置摩擦系数。 var density: CGFloat // 设置相对密度 1 by default var resistance: CGFloat // 线性阻力系数。

(0--CGFLOAT_MAX) var angularResistance: CGFloat // 设置角度阻力系数(0--CGFLOAT_MAX) var allowsRotation: Bool // 设置行为中的dynamic item能否够循环 // The linear velocity, expressed in points per second, that you want to add to the specified dynamic item // If called before being associated to an animator, the behavior will accumulate values until being associated to an animator func addLinearVelocity(velocity: CGPoint, forItem item: UIDynamicItem)//向dynamic item添加线速度属性。单位点 func linearVelocityForItem(item: UIDynamicItem) -> CGPoint // The angular velocity, expressed in radians per second, that you want to add to the specified dynamic item // If called before being associated to an animator, the behavior will accumulate values until being associated to an animator func addAngularVelocity(velocity: CGFloat, forItem item: UIDynamicItem)//向dynamic item添加角速度属性。单位弧度 func angularVelocityForItem(item: UIDynamicItem) -> CGFloat

注意: 假设向同一个动力动画加入多个UIDynamicItemBehavior实例。仅仅会应用一套属性描写叙述(交集?)多个UIDynamicItemBehavior实例配置同个属性时,使用最后的。

(2)物理仿真行为须知
上述全部物理仿真行为都继承自UIDynamicBehavior
UIDynamicBehavior配置:
func addChildBehavior(behavior: UIDynamicBehavior!)//向自己定义的UIDynamicBehavior加入子行为
func removeChildBehavior(behavior: UIDynamicBehavior)//删除自己定义的UIDynamicBehavior的子行为
var childBehaviors: [AnyObject] { get }//返回自己定义UIDynamicBehavior的子行为数组
// When running, the dynamic animator calls the action block on every animation step.
var action: (() -> Void)!//在UIDynamicAnimator运行过程中每一步都会调用的语句块
func willMoveToAnimator(dynamicAnimator: UIDynamicAnimator?) // nil when being removed from an animator
var dynamicAnimator: UIDynamicAnimator? { get }

4.物理仿真器
(1)物理仿真器须知
它能够让物理仿真元素运行物理仿真行为
它是UIDynamicAnimator类型的对象
• 提供动力行为的上下文
• 依据ref view确定坐标系
• 控制动力引擎
• 维护着动力行为的状态

(2)UIDynamicAnimator的初始化
init(referenceView view: UIView)
view參数:是一个參照视图。表示物理仿真的范围
(3)UIDynamicAnimator的常见方法
func addBehavior(behavior: UIDynamicBehavior!)//加入1个物理仿真行为
func removeBehavior(behavior: UIDynamicBehavior!)//移除1个物理仿真行为
func removeAllBehaviors()//移除之前加入过的全部物理仿真行为
func itemsInRect(rect: CGRect) -> [AnyObject]//返回贯穿指定区域的全部dynamic item。


func elapsedTime() -> NSTimeInterval//返回动画開始到如今的时间间隔。


func updateItemUsingCurrentState(item: UIDynamicItem)//(更新dynamic item在UIDynamicAnimator内部的代表的状态),dynamic item被加入到UIDynamicAnimator后。你更改了dynamic item的状态。你应该使用这种方法更新dynamic item的状态
init(collectionViewLayout layout: UICollectionViewLayout) //在collection views上使用动力动画,collection view layout的坐标系作为动力行为和动力项的坐标系。动力项必须为UICollectionViewLayoutAttributes对象。可使用 setTranslatesReferenceBoundsIntoBoundaryWithInsets:设置碰撞动力界限(相对于 collection view layout的坐标系),当collection view layout发生改变时,会自己主动调用invalidateLayout、暂停、又一次開始动力

func layoutAttributesForCellAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes!//返回指定位置collection view cell的布局属性
func layoutAttributesForSupplementaryViewOfKind(kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes!//返回indexPath位置上collection view cell的指定(用kind指定)SupplementaryView的布局属性。

func layoutAttributesForDecorationViewOfKind(decorationViewKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes!//返回indexPath位置上collection view cell的指定(用decorationViewKind指定)decorationView的布局属性。

(4)UIDynamicAnimator的常见属性
var referenceView: UIView? { get }//參照视图
var behaviors: [AnyObject] { get }//加入到物理仿真器中的全部物理仿真行为
var running: Bool { get }//是否正在进行物理仿真

unowned(unsafe) var delegate: UIDynamicAnimatorDelegate?//代理对象(能监听物理仿真器的仿真过程,比方開始和结束)

(5) UIDynamicAnimator的代理
protocol UIDynamicAnimatorDelegate : NSObjectProtocol {
optional func dynamicAnimatorWillResume(animator: UIDynamicAnimator)//UIDynamicAnimator将要启动的时候会调用
optional func dynamicAnimatorDidPause(animator: UIDynamicAnimator)//UIDynamicAnimator已经停止的时候会调用
}

原文地址:https://www.cnblogs.com/mengfanrong/p/5205461.html