版本記錄
| 版本號(hào) | 時(shí)間 |
|---|---|
| V1.0 | 2018.08.05 |
前言
iOS中有關(guān)視圖控件用戶能看到的都在UIKit框架里面,用戶交互也是通過UIKit進(jìn)行的,這一篇就看一下UIKit動(dòng)力學(xué)和移動(dòng)效果。
簡(jiǎn)介
UIKit Dynamics是集成到UIKit的完整物理引擎。 它允許您通過添加諸如重力,附件(彈簧)和力等行為來創(chuàng)建感覺真實(shí)的界面。 您可以定義您希望界面元素采用的物理特征,動(dòng)態(tài)引擎負(fù)責(zé)其余部分。
Motion Effects可讓您創(chuàng)建酷炫的視差效果,基本上,您可以利用手機(jī)加速度計(jì)提供的數(shù)據(jù)來創(chuàng)建對(duì)手機(jī)方向變化做出反應(yīng)的界面。
在一起使用時(shí),motion 和 dynamics 形成了用戶體驗(yàn)工具的強(qiáng)大動(dòng)力,使您的數(shù)字接口變得生動(dòng)。 通過讓用戶以自然,動(dòng)態(tài)的方式響應(yīng)他們的操作,您的用戶將在更深層次上與您的應(yīng)用程序建立聯(lián)系。
UIKit動(dòng)力學(xué)可以帶來很多樂趣,開始學(xué)習(xí)它們的最好方法是先看一些小例子。
新建立工程,并在sb中拖進(jìn)去一個(gè)控件并設(shè)置好約束。

運(yùn)行起來,如下所示的界面,這個(gè)是再平常不過的界面了,任何一個(gè)初學(xué)者都會(huì)做的一個(gè)界面。

如果您在物理設(shè)備上運(yùn)行應(yīng)用,請(qǐng)嘗試傾斜手機(jī),將其顛倒,甚至搖晃,這些都是框架正常的設(shè)計(jì)和反應(yīng)。當(dāng)您向界面添加視圖時(shí),您希望它可以按照框架的定義牢固地固定到位 - 直到您為界面添加一些動(dòng)態(tài)真實(shí)感!
Adding gravity - 增加重力
我們繼續(xù)在上面的工程中添加代碼,在viewDidLoad中添加屬性。
Swift版本
var animator: UIDynamicAnimator!
var gravity: UIGravityBehavior!
這些屬性是隱式解包的選項(xiàng)(在類型名稱后面用!表示)。 這些屬性必須是可選的,因?yàn)槟粫?huì)在我們類的init方法中初始化它們。 您可以使用隱式解包的選項(xiàng),因?yàn)槲覀冎涝诔跏蓟鼈冎筮@些屬性不會(huì)為nil。 這可以防止您不得不使用!運(yùn)算符進(jìn)行手動(dòng)解包。
繼續(xù)添加swift代碼
animator = UIDynamicAnimator(referenceView: view)
gravity = UIGravityBehavior(items: [square])
animator.addBehavior(gravity)
OC版本
下面是OC版本的,我還是直接上代碼了。
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *dynamicView;
@end
@implementation ViewController
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.dynamicView]];
[animator addBehavior:gravity];
}
@end
這樣寫完在真機(jī)上開始運(yùn)行,就會(huì)發(fā)現(xiàn)沒有任何重力下墜的效果,這是為什么?最后檢查發(fā)現(xiàn)就是因?yàn)?code>animator和gravity是局部變量,當(dāng)viewDidLoad執(zhí)行完就銷毀了,所以就沒有任何重力效果了,解決方法也很簡(jiǎn)單就是將這兩個(gè)對(duì)象設(shè)置為屬性,讓VC去持有,那么就不會(huì)銷毀就有效果了,代碼如下所示:
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *dynamicView;
@property (nonatomic, strong) UIGravityBehavior *gravity;
@property (nonatomic, strong) UIDynamicAnimator *animator;
@end
@implementation ViewController
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
self.animator = animator;
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.dynamicView]];
self.gravity = gravity;
[animator addBehavior:gravity];
}
@end
運(yùn)行效果如下所示:

在您剛剛添加的代碼中,這里有幾個(gè)動(dòng)態(tài)類:
-
UIDynamicAnimator是UIKit物理引擎。此類跟蹤您添加到引擎的各種行為,例如重力,并提供整體上下文。在創(chuàng)建動(dòng)畫制作器的實(shí)例時(shí),可以傳入animator用來定義其坐標(biāo)系的參考視圖。 -
UIGravityBehavior模擬重力的行為并對(duì)一個(gè)或多個(gè)項(xiàng)目施加力,允許您對(duì)物理交互進(jìn)行建模。創(chuàng)建行為實(shí)例時(shí),將其與一組項(xiàng)目(通常是視圖)相關(guān)聯(lián)。通過這種方式,您可以選擇受行為影響的項(xiàng)目,在這種情況下,重力影響哪些項(xiàng)目。
大多數(shù)行為都有許多配置屬性,例如,重力行為允許您改變其角度和大小。嘗試修改這些屬性,使對(duì)象以不同的加速度下降,側(cè)向或?qū)恰?/p>
注意:關(guān)于單位的快速說明:在物理世界中,重力(g)以米/秒平方表示,大約等于
9.8 m/s2。使用牛頓第二定律,您可以使用以下公式計(jì)算物體在重力影響下的落差范圍,其實(shí)就是我們高中物理所學(xué)的 s=1/2gt2
distance = 0.5 × g × time2
在UIKit Dynamics中,公式相同但單位不同。 而不是米,你使用每秒數(shù)千像素的單位。 使用牛頓第二定律,您仍然可以根據(jù)您提供的重力組件隨時(shí)精確計(jì)算出您的視圖。
你真的需要知道這一切嗎? 并不是,所有你真正需要知道的是,g更大的值意味著物體會(huì)更快下降,但理解下面的數(shù)學(xué)永遠(yuǎn)不會(huì)有任何壞處,算是錦上添花吧。
Setting boundaries - 設(shè)置邊界
雖然你看不到它,但即使它從屏幕底部消失,它也會(huì)繼續(xù)下降。 為了使其保持在屏幕范圍內(nèi),您需要定義邊界。
Swift版本
var collision: UICollisionBehavior!
在viewDidLoad中添加如下代碼:
collision = UICollisionBehavior(items: [square])
collision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(collision)
OC版本
@property (nonatomic, strong) UICollisionBehavior *collision;
UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.dynamicView]];
self.collision = collision;
collision.translatesReferenceBoundsIntoBoundary = YES;
[animator addBehavior:collision];
上面的代碼創(chuàng)建了一個(gè)碰撞行為,它定義了一個(gè)或多個(gè)相關(guān)項(xiàng)與之交互的邊界。
上述代碼不是顯式添加邊界坐標(biāo),而是將translatesReferenceBoundsIntoBoundary屬性設(shè)置為true。 這會(huì)導(dǎo)致邊界使用提供給UIDynamicAnimator的參考視圖的邊界。運(yùn)行,你會(huì)看到正方形與屏幕底部碰撞,彈跳一點(diǎn),然后停下來,正如下所示。

這是一個(gè)非常令人印象深刻的行為,特別是當(dāng)你考慮到你在這一點(diǎn)上添加了多少代碼時(shí)。
Handling collisions - 處理碰撞
接下來你將添加一個(gè)不可移動(dòng)的障礙,落下的方塊將碰撞和相互作用。將以下代碼插入viewDidLoad中將方塊視圖添加到視圖的行之后。
Swift版本
let barrier = UIView(frame: CGRect(x: 0, y: 300, width: 130, height: 20))
barrier.backgroundColor = UIColor.redColor()
view.addSubview(barrier)
OC版本
首先是在sb中拖進(jìn)去一個(gè)barrier障礙的UIView控件,然后設(shè)置約束。

然后我們運(yùn)行,看這個(gè)barrier是否起到了障礙的作用。

你會(huì)看到一個(gè)紅色的“障礙”延伸到屏幕的中間。 然而,事實(shí)證明,當(dāng)方塊視圖時(shí)直接穿過障礙時(shí),障礙不是那么有效。
這并不是你想要的效果,但確實(shí)提供了一個(gè)重要的提醒:dynamics只會(huì)影響與行為相關(guān)的視圖。
看一下下面這個(gè)示意圖

上面的Red Barrier就是紅色的障礙,Square就是我們的方塊視圖。
UIDynamicAnimator與提供坐標(biāo)系的參考視圖相關(guān)聯(lián)。 然后添加一個(gè)或多個(gè)行為,對(duì)與其關(guān)聯(lián)的item施加力。 大多數(shù)行為可以與多個(gè)item相關(guān)聯(lián),并且每個(gè)item可以與多個(gè)行為相關(guān)聯(lián)。 上圖顯示了您應(yīng)用中的當(dāng)前行為及其關(guān)聯(lián)。
當(dāng)前代碼中的任何行為都沒有“意識(shí)到”障礙那個(gè)視圖,因此就底層動(dòng)力學(xué)引擎而言,障礙甚至不存在。
Making objects respond to collisions - 使對(duì)象響應(yīng)collisions
要使方塊視圖與屏障barrier發(fā)生碰撞,請(qǐng)找到初始化碰撞行為的行并將其替換為以下內(nèi)容:
Swift版本
collision = UICollisionBehavior(items: [square, barrier])
OC版本
@property (weak, nonatomic) IBOutlet UIView *barrierView;
UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.dynamicView, self.barrierView]];
也就是說碰到行為影響到的數(shù)組參數(shù)中添加self.barrierView,這樣才會(huì)給這個(gè)視圖添加碰撞行為。
下面我們就看一下實(shí)際運(yùn)行效果。

碰撞行為在與其相關(guān)聯(lián)的每個(gè)item周圍形成一個(gè)boundary,這會(huì)將它們從可以相互傳遞的對(duì)象變?yōu)楦訄?jiān)固的東西。
更新前面的圖表,您可以看到碰撞行為現(xiàn)在與兩個(gè)視圖相關(guān)聯(lián):

但是,兩個(gè)對(duì)象之間的交互仍然存在一些不太恰當(dāng)?shù)膯栴}。 障礙物應(yīng)該是不可移動(dòng)的,但當(dāng)兩個(gè)物體在你當(dāng)前的配置中發(fā)生碰撞時(shí),障礙物會(huì)被撞掉并開始向屏幕底部旋轉(zhuǎn)。
更奇怪的是,障礙物從屏幕底部反彈并且不像方塊視圖那樣穩(wěn)定下來 - 這是有道理的,因?yàn)橹亓π袨椴粫?huì)與屏障相互作用。 這也解釋了為什么屏障在正方形與之碰撞之前不會(huì)移動(dòng)。
看起來您需要一種不同的方法來解決問題。 由于屏障視圖是不可移動(dòng)的,因此dynamics引擎不需要知道它的存在。 但是如何檢測(cè)到碰撞?
限于篇幅,下一篇繼續(xù)~~~
參考文章
1. iOS7 UIKit動(dòng)力學(xué)-重力特性UIGravityBehavior
2. Objective-C學(xué)習(xí)之UIGravityBehavior仿真行為(重力、碰撞)
3. UIGravityBehavior isn't working
后記
本篇主要講述了UIKit動(dòng)力學(xué)和移動(dòng)效果,感興趣的給個(gè)贊或者關(guān)注~~~~
