本文翻譯自Chris Grant的《iOS9 Day-by-Day :: Day 9 :: UIKit Dynamics》(https://www.shinobicontrols.com/blog/ios9-day-by-day-day9-uikit-dynamics)揽惹。感謝Chris Grant的辛苦工作宁昭!
iOS 7開始引入了UIKit Dynamics惑申,用來幫助開發(fā)者給界面添加真實(shí)的物理效果刻伊。在這個(gè)文章中將會(huì)看到封拧,iOS 9進(jìn)一步引入了許多新的內(nèi)容。
非矩形碰撞邊緣
在iOS 9以前碰逸,UIKitDynamics框架只支持矩形邊緣碰撞饰抒。這樣會(huì)導(dǎo)致非矩形物體碰撞時(shí)產(chǎn)生奇怪的視覺效果。iOS 9支持三種類型的碰撞邊緣:矩形脑漫、橢圓和路徑髓抑。其中路徑可以是任意逆時(shí)針并且不會(huì)自相交的形狀。有一點(diǎn)需要注意的是优幸,路徑只支持凸多邊形吨拍,而不支持凹多邊形。
通過子類化UIView
可以提供自定義的碰撞邊緣類型网杆。
class Ellipse: UIView {
override var collisionBoundsType: UIDynamicItemCollisionBoundsType {
return .Ellipse
}
}
對于自定義碰撞邊緣路徑的視圖羹饰,也可以這樣處理。
UIFieldBehavior
iOS 9以前只支持重力場效應(yīng)跛璧。這時(shí)其實(shí)已經(jīng)存在UIFieldBehavior
類严里,只是SDK中還沒有通過子類將這些API暴露給用戶。
UIKit Dynamics中包含一下幾種場效應(yīng):
- 線性重力場(Linear Gravity)
- 徑向重力場(Radial Gravity)
- 噪聲(Noise)
- 自定義(Custom)
這些行為都有一系列的屬性進(jìn)行配置追城,從而對UIDynamicsAnimator
中的視圖造成影響。它們的使用方法都非常簡單燥撞。
構(gòu)建一個(gè)UIFieldBehavior和不規(guī)則碰撞邊緣的例子
讓我們在下面的例子里組合使用這兩個(gè)新特征座柱。首先我們需要一對視圖(一個(gè)橢圓和一個(gè)方塊),并且添加一些碰撞邏輯以及一個(gè)噪聲場(UIFieldBehavior
)物舒。
為了使用UIKit Dynamics色洞,首先需要設(shè)置UIDynamicAnimator
。我們在視圖控制器中設(shè)置一個(gè)變量來引用它冠胯。
// Set up a UIDynamicAnimator on the view.
animator = UIDynamicAnimator(referenceView: view)
設(shè)置需要執(zhí)行動(dòng)畫的視圖:
// Add two views to the view
let square = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
square.backgroundColor = .blueColor()
view.addSubview(square)
let ellipse = Ellipse(frame: CGRect(x: 0, y: 100, width: 100, height: 100))
ellipse.backgroundColor = .yellowColor()
ellipse.layer.cornerRadius = 50
view.addSubview(ellipse)
給視圖添加重力行為:
let items = [square, ellipse]
// Create some gravity so the items always fall towards the bottom.
let gravity = UIGravityBehavior(items: items)
animator.addBehavior(gravity)
添加噪音:
let noiseField:UIFieldBehavior = UIFieldBehavior.noiseFieldWithSmoothness(1.0, animationSpeed: 0.5)
// Set up the noise field
noiseField.addItem(square)
noiseField.addItem(ellipse)
noiseField.strength = 0.5
animator.addBehavior(noiseField)
使用noiseFieldWithSmoothness
創(chuàng)建一個(gè)噪音場火诸,并且將矩形和橢圓添加到這個(gè)行為中。
// Don't let objects overlap each other - set up a collide behaviour
let collision = UICollisionBehavior(items: items)
collision.setTranslatesReferenceBoundsIntoBoundaryWithInsets(UIEdgeInsets(top: 20, left: 5, bottom: 5, right: 5))
animator.addBehavior(collision)
UICollisionBehavior
的setTranslatesReferenceBoundsIntoBoundaryWithInsets
方法可以創(chuàng)建一個(gè)矩形盒子荠察,允許視圖與邊緣發(fā)生碰撞置蜀。如果不使用這個(gè)碰撞盒,這兩個(gè)視圖可能會(huì)從下面掉出可視區(qū)域悉盆。
提到重力盯荤,如果它每次都指向設(shè)備的底部,用戶體驗(yàn)更好焕盟。換句話說秋秤,就是我們應(yīng)該使用現(xiàn)實(shí)世界中重力的方向。我們使用CoreMotion
框架來獲取重力方向。
let manager:CMMotionManager = CMMotionManager()
為了持續(xù)的獲取方向的變化灼卢,我們需要一個(gè)引用該管理器的屬性绍哎。一旦開始獲取設(shè)備的動(dòng)作更新,我們就可以根據(jù)設(shè)備管理器的gravity
屬性更新重力行為的gravityDirection
鞋真。
// Used to alter the gravity so it always points down.
if manager.deviceMotionAvailable {
manager.deviceMotionUpdateInterval = 0.1
manager.startDeviceMotionUpdatesToQueue(NSOperationQueue.mainQueue(), withHandler:{
deviceManager, error in
gravity.gravityDirection = CGVector(dx: deviceManager!.gravity.x, dy: -deviceManager!.gravity.y)
})
}
注意蛇摸,這里只支持垂直方向的變化,如果需要支持所有的方向灿巧,應(yīng)該進(jìn)行額外的計(jì)算赶袄。
剛才的小矩形會(huì)在屏幕上到處移動(dòng),但是看不出來到底在發(fā)生什么事情抠藕。在WWDC session 229中饿肺,蘋果提供了一種可視化的動(dòng)畫調(diào)試方法。我們只需要給項(xiàng)目添加一個(gè)頭文件盾似,并加入一下代碼:
@import UIKit;
#if DEBUG
@interface UIDynamicAnimator (AAPLDebugInterfaceOnly)
/// Use this property for debug purposes when testing.
@property (nonatomic, getter=isDebugEnabled) BOOL debugEnabled;
@end
#endif
這樣會(huì)暴露UIDynamicAnimator
的一些啟用調(diào)試模式的私有API敬辣。一旦啟用了調(diào)試模式,我們就可以看到視圖的受力情況零院「仍荆回到ViewController
類,啟用調(diào)試模式告抄。
animator.debugEnabled = true // Private API. See the bridging header.
這樣撰茎,一旦我們啟動(dòng)應(yīng)用程序,就可以看到UIFiledBehavior
的作用打洼。
我們同樣可以看到視圖的碰撞邊框以及矩形和方塊的碰撞邊緣龄糊。在lldb還有一些其它的調(diào)試屬性,比如debugInterval
和debugAnimationSpeed
募疮。它們?yōu)檎{(diào)試UIKit Dynamics提供幫助炫惩。
我們可以看到場效應(yīng)對視圖的力的作用“⑴ǎ可以通過設(shè)置場效應(yīng)的對象的屬性來改變視圖的行為他嚷。我們通過添加一些控件來調(diào)節(jié)這些屬性。打開Interface Builder并添加三個(gè)UISlider
控件芭毙。第一個(gè)控制場效應(yīng)的強(qiáng)度裳仆,第二個(gè)控制平滑度袋倔,最后一個(gè)控制速度硅堆。其中強(qiáng)度的變化方位是0-25皂冰,其它兩個(gè)是0-1。
一旦在Interface Buider中設(shè)置好這些控件苛聘,就可以通過拖拽連接控件與ViewController
類涂炎。
@IBAction func smoothnessValueChanged(sender: UISlider) {
noiseField.smoothness = CGFloat(sender.value)
}
@IBAction func speedValueChanged(sender: UISlider) {
noiseField.animationSpeed = CGFloat(sender.value)
}
@IBAction func strengthValueChanged(sender: UISlider) {
noiseField.strength = CGFloat(sender.value)
}
這樣忠聚,程序運(yùn)行后就可以通過控制三個(gè)屬性來觀察不同組合所產(chǎn)生的影響。
希望本文能夠給大家對UIFieldBehavior
以及非矩形碰撞邊框的API的使用和調(diào)試提供一個(gè)大體的印象唱捣。建議大家在真機(jī)上運(yùn)行這個(gè)程序两蟀,這樣就可以充分利用動(dòng)作傳感器的效果。
更多信息
關(guān)于UIKit Dynamics新特性的更多信息震缭,可以看一下WWDC session 229(What's New in UIKit Dynamics and Visual Effects)的前半部分赂毯。別忘了在GitHub上還可以下到示例代碼。
戴維營教育
戴維營教育(Dive In Education)拣宰,潛心做IT職業(yè)教育党涕!緊跟時(shí)代潮流,不弄虛作假巡社!不忘初心膛堤!
- 官網(wǎng):戴維營教育http://www.diveinedu.com
- 在線視頻:戴維營學(xué)院http://v.diveinedu.com
- 問答網(wǎng):潛心俱樂部http://divein.club