UIKit框架(一) —— UIKit动力学和移动效果(一)

版本记录

版本号 时间
V1.0 2018.08.05

前言

iOS中有关视图控件用户能看到的都在UIKit框架里面,用户交互也是通过UIKit进行的,这一篇就看一下UIKit动力学和移动效果。

简介

UIKit Dynamics是集成到UIKit的完整物理引擎。 它允许您通过添加诸如重力,附件(弹簧)和力等行为来创建感觉真实的界面。 您可以定义您希望界面元素采用的物理特征,动态引擎负责其余部分。

Motion Effects可让您创建酷炫的视差效果,基本上,您可以利用手机加速度计提供的数据来创建对手机方向变化做出反应的界面。

在一起使用时,motiondynamics 形成了用户体验工具的强大动力,使您的数字接口变得生动。 通过让用户以自然,动态的方式响应他们的操作,您的用户将在更深层次上与您的应用程序建立联系。

UIKit动力学可以带来很多乐趣,开始学习它们的最好方法是先看一些小例子。

新建立工程,并在sb中拖进去一个控件并设置好约束。

运行起来,如下所示的界面,这个是再平常不过的界面了,任何一个初学者都会做的一个界面。

如果您在物理设备上运行应用,请尝试倾斜手机,将其颠倒,甚至摇晃,这些都是框架正常的设计和反应。当您向界面添加视图时,您希望它可以按照框架的定义牢固地固定到位 - 直到您为界面添加一些动态真实感!


Adding gravity - 增加重力

我们继续在上面的工程中添加代码,在viewDidLoad中添加属性。

Swift版本

var animator: UIDynamicAnimator!
var gravity: UIGravityBehavior!

这些属性是隐式解包的选项(在类型名称后面用!表示)。 这些属性必须是可选的,因为您不会在我们类的init方法中初始化它们。 您可以使用隐式解包的选项,因为我们知道在初始化它们之后这些属性不会为nil。 这可以防止您不得不使用!运算符进行手动解包。

继续添加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

这样写完在真机上开始运行,就会发现没有任何重力下坠的效果,这是为什么?最后检查发现就是因为animatorgravity是局部变量,当viewDidLoad执行完就销毁了,所以就没有任何重力效果了,解决方法也很简单就是将这两个对象设置为属性,让VC去持有,那么就不会销毁就有效果了,代码如下所示:

#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

运行效果如下所示:

在您刚刚添加的代码中,这里有几个动态类:

  • UIDynamicAnimator是UIKit物理引擎。此类跟踪您添加到引擎的各种行为,例如重力,并提供整体上下文。在创建动画制作器的实例时,可以传入animator用来定义其坐标系的参考视图。
  • UIGravityBehavior模拟重力的行为并对一个或多个项目施加力,允许您对物理交互进行建模。创建行为实例时,将其与一组项目(通常是视图)相关联。通过这种方式,您可以选择受行为影响的项目,在这种情况下,重力影响哪些项目。

大多数行为都有许多配置属性,例如,重力行为允许您改变其角度和大小。尝试修改这些属性,使对象以不同的加速度下降,侧向或对角。

注意:关于单位的快速说明:在物理世界中,重力(g)以米/秒平方表示,大约等于9.8 m/s2。使用牛顿第二定律,您可以使用以下公式计算物体在重力影响下的落差范围,其实就是我们高中物理所学的 s=1/2gt2

distance = 0.5 × g × time2

UIKit Dynamics中,公式相同但单位不同。 而不是米,你使用每秒数千像素的单位。 使用牛顿第二定律,您仍然可以根据您提供的重力组件随时精确计算出您的视图。

你真的需要知道这一切吗? 并不是,所有你真正需要知道的是,g更大的值意味着物体会更快下降,但理解下面的数学永远不会有任何坏处,算是锦上添花吧。


Setting boundaries - 设置边界

虽然你看不到它,但即使它从屏幕底部消失,它也会继续下降。 为了使其保持在屏幕范围内,您需要定义边界。

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];

上面的代码创建了一个碰撞行为,它定义了一个或多个相关项与之交互的边界。

上述代码不是显式添加边界坐标,而是将translatesReferenceBoundsIntoBoundary属性设置为true。 这会导致边界使用提供给UIDynamicAnimator的参考视图的边界。运行,你会看到正方形与屏幕底部碰撞,弹跳一点,然后停下来,正如下所示。

这是一个非常令人印象深刻的行为,特别是当你考虑到你在这一点上添加了多少代码时。


Handling collisions - 处理碰撞

接下来你将添加一个不可移动的障碍,落下的方块将碰撞和相互作用。将以下代码插入viewDidLoad中将方块视图添加到视图的行之后。

Swift版本

let barrier = UIView(frame: CGRect(x: 0, y: 300, width: 130, height: 20))
barrier.backgroundColor = UIColor.redColor()
view.addSubview(barrier)

OC版本

首先是在sb中拖进去一个barrier障碍的UIView控件,然后设置约束。

然后我们运行,看这个barrier是否起到了障碍的作用。

你会看到一个红色的“障碍”延伸到屏幕的中间。 然而,事实证明,当方块视图时直接穿过障碍时,障碍不是那么有效。

这并不是你想要的效果,但确实提供了一个重要的提醒:dynamics只会影响与行为相关的视图。

看一下下面这个示意图

上面的Red Barrier就是红色的障碍,Square就是我们的方块视图。

UIDynamicAnimator与提供坐标系的参考视图相关联。 然后添加一个或多个行为,对与其关联的item施加力。 大多数行为可以与多个item相关联,并且每个item可以与多个行为相关联。 上图显示了您应用中的当前行为及其关联。

当前代码中的任何行为都没有“意识到”障碍那个视图,因此就底层动力学引擎而言,障碍甚至不存在。


Making objects respond to collisions - 使对象响应collisions

要使方块视图与屏障barrier发生碰撞,请找到初始化碰撞行为的行并将其替换为以下内容:

Swift版本

collision = UICollisionBehavior(items: [square, barrier])

OC版本

@property (weak, nonatomic) IBOutlet UIView *barrierView;

UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.dynamicView, self.barrierView]];

也就是说碰到行为影响到的数组参数中添加self.barrierView,这样才会给这个视图添加碰撞行为。

下面我们就看一下实际运行效果。

碰撞行为在与其相关联的每个item周围形成一个boundary,这会将它们从可以相互传递的对象变为更加坚固的东西。

更新前面的图表,您可以看到碰撞行为现在与两个视图相关联:

但是,两个对象之间的交互仍然存在一些不太恰当的问题。 障碍物应该是不可移动的,但当两个物体在你当前的配置中发生碰撞时,障碍物会被撞掉并开始向屏幕底部旋转。

更奇怪的是,障碍物从屏幕底部反弹并且不像方块视图那样稳定下来 - 这是有道理的,因为重力行为不会与屏障相互作用。 这也解释了为什么屏障在正方形与之碰撞之前不会移动。

看起来您需要一种不同的方法来解决问题。 由于屏障视图是不可移动的,因此dynamics引擎不需要知道它的存在。 但是如何检测到碰撞?

限于篇幅,下一篇继续~~~

参考文章

1. iOS7 UIKit动力学-重力特性UIGravityBehavior
2. Objective-C学习之UIGravityBehavior仿真行为(重力、碰撞)
3. UIGravityBehavior isn't working

后记

本篇主要讲述了UIKit动力学和移动效果,感兴趣的给个赞或者关注~~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容