如何在iOS7中使用UIKit动力之UICollisionbehavior是可数名词吗

iOS7 UIKit动力学-碰撞特性UICollisionBehavior 上 - CSDN博客
上文我们讲到了重力属性UIGravityBehavior这个类。很明显当我们为视图加上了重力的属性之后,这个苹果的UIview就如同掉入了无底洞,不断地下坠,不断的加速。而现在呢,我们要在这个手机屏幕上,添加一个地面。使不断下落的苹果最终有一个着陆点。那么我们如何为这个视图添加一个地面呢,如下(当前内容承接上文内容,如有问题,请看上文:):
首先在.h文件中创建一个UICollisionBehavior对象
#import &UIKit/UIKit.h&
@interface ViewController : UIViewController
UIDynamicAnimator * _
UIGravityBehavior * _
UICollisionBehavior * _
然后在.m文件中为UICollisionBehavior对象进行初始化,并为apple对象设置边框属性。
- (void)viewDidLoad
[super viewDidLoad];
UIView * apple = [[UIView alloc] initWithFrame:CGRectMake(40,40, 40, 40)];
apple.backgroundColor = [UIColor redColor];
[self.view addSubview:apple];
_animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
_gravity = [[UIGravityBehavior alloc] initWithItems:@[apple]];
[_animator addBehavior:_gravity];
UICollisionBehavior
_ground = [[UICollisionBehavior alloc] initWithItems:@[apple]];
_ground.translatesReferenceBoundsIntoBoundary = YES;
[_animator addBehavior:_ground];
这里,以上的代码创建了一个碰撞的行为,它定义了一个或者多个边界交互的特性,这里没有显示的为各个空间添加边界,而是隐式的调用了一个UICollisionBehavior的属性translatesReferenceBoundsIntoBoundary,将这个属性设置为YES之后。会使边界引用使用视图提供的UIDynamicAnimator边界。构建和运行,你就会看到效果,apple落到地上弹起来了,又重新落到地上。
点击关注我,更多精彩内容!!!& & 前言:& & 学完了底层c,c++之后,现在开始重新回头进行上层的界面设计。既然做了就要做好,就如同过去c,c++做的一样。过去的一年的时间精看了深入浅出mfc,C++程序设计语言,effective-c++,GOF和大话设计模式,粗看了more effective c++, c++ premier,linux程序设计,harly guide linux, 自觉在c++方面的战果还算不错,现在重新捡起刚从事半年多的ios,一方面是因为money,另一方面是因为过去确实底层能力不行,对于界面处于知其然而不知其所以然的状态,现在重新看起,书籍一定是必需品了。买了两本书,ios开发指南和ios设计模式解析。这一段博客主要记录书籍的学习过程,还有过去的未竟的任务,将好的思想,好的策略浓缩一下便于为我所用。ios开发指南& & 国人写的书,一直对国人的技术书籍有种抵触情绪,不过看这本书的目录结构比较适合我,于是放弃了精通ios开发那本而选择了这本。这本书有点太厚了,接近700页,拿在手上不适合,太重,讲的东西多,但是不算杂,各项均有涉及,有个别错误,内容不算高深,适合我这样的小半桶水看。ios设计模式解析是没有时间看了,先让它睡着吧,把基本的捡起来以便于自己好迅速的上手公司的代码,要不然以后工作有我受的了。第一章& & xcode简介,书籍图片,内容介绍,书中源码链接。没啥有太大意义的内容。第二章& & 应用程序的生命周期值得读一读。& & 打开程序: Not Run (applicationDidFinishLauch) ->InActive (ApplicationDidBecomeActive)->Active& & 程序后台:
Active (applicationWillResignActive) ->InActive ->Backgroud (applicationDidEnterBackgroud)->Suspend (applciationWillTerminate) ->Terminate& & 挂起运行:
Suspend ->Backgroud (applciationWillEnterForgroud) ->InActive (applicationWillBecomeActive) ->Active& & 当系统内存不足的时候,后台的Suspend程序有可能会被系统kill掉,没有通知。& & 视图的生命周期& & loadView(得到一个view) ->ViewDidLoad(在生成的view后添加subview以进行自我的定制) ->ViewWillAppear ->viewWillDisappear ->didReceiveMemoryWarnning (收到内存警告) ->viewDidUnLoad& & loadView是为了创建self.view,当从nib文件中去加载就会直接创建self.view,因此loadView也就不需要了。& & Xcode的project和target& & 一个project对应这多个target,project的设置是公共的,target的设置可以覆盖project的设置。在target的summary选项下,设置屏幕图标57*57, Icon.png,retina屏幕为Icon@2x.png, 启动屏幕为320*480,Default.png或者retina屏幕为Default@2x.png, 设备支持选项。& & ios Api简介& & 框架太多,不容易记忆,再说必要性不是很大。注意大的有四个层次: Cocoa Touch,
Core Services, Core OS。具体的每一个层次包含什么,暂时不关心。还有如何使用帮助文档,alt+鼠标点击-》打开帮助文档第三章 基本的设计模式& & ios常用设计模式,这个我比较擅长,相对就简单多了。单例模式& & 没有使用synchronized机制,使用gcd的一种dispatch_once机制来维护仅仅执行一次的操作,比加锁效率高一些,至于内部原理,暂时不懂,不过以后会搞定它的底层的。来个简单代码示例便于以后copy& & @interface Singleton : NSObject& & @end& & @implementation Singleton& & static Singleton *_shareSingleton =& & + (Singleton*) sharedManager& & {& & static dispatch_once_& & dispatch_once(&once, ^{& & _shareSingleton = [[Singleton alloc]init];& & //...... your other initial code here& & }& & );& & return _shareS& & }& & 思想很简单,私有静态指针,类方法中分配内存并返回这个指针。为了防止多线程同时访问可能会创建几个对象,可以采用加锁,为了提高效率,有一种二次探测的策略;这里采用的GCD的内容保证只执行一次。& & 示例: UIAccelerometer NSUserDefault NSNotificationCenter等等。委托模式& & 我比较挠头的一种模式,说起来就是我定义了一个框架,但是又想给使用者以个性化的操作,于是将个性化的操作提取出来,制作成协议,让客户去实现协议。举个UITableView的例子, ViewController实现UITableViewDelegate协议, viewController持有一个UItableView的指针,设置tableView.delegate = self。这样tableView相当于将个性化的操纵留给了ViewController去完成了。& & 简单类图:& & UITableViewDelegate& & |& & |& & UITableView (持有delegate指针)------------->MyViewController(持有tableView指针,并设置delegate)& & MyViewController继承delegate同时持有tableView的指针,这个是一个强引用。UITableView也持有一个delegate指针,由于这个指针最终要赋值为MyViewController对象,因此为了避免循环引用,一定是一个弱引用。一般是在MyViewControlller中设置tableView.delegate为自身,也就是说MyViewController负责实现delegate方法。这样UITableView自身实现了TableView的基本框架,同时将用户的个性化的可扩展的地方弄成协议供客户实现。协议的调用肯定是UITableView内部框架去做的,它需要数据的时候就去协议要数据,协议呢给用户以最大的扩展性,同时用户有不用关心UITableView具体的内部是如何呈现了,用户只需要提供数据就行了。示例 UITextField Application观察者模式& & 相当简单的一种设计模式,但是又相当常用。一定要记住一个Subject,n多个Observer。Subject需要实现addObserver,removeObserver,notifyAllObservers的方法,同时有一个observers数组保存所有的observer;observer需要实现update方法。当需要更新数据的时候,调用notifyAllObservers方法,这个方法中遍历数组的所有observer,调用observer的update方法去更新数据。通知中心就是一个subject,为了方便使用它以单例模式实现的,后面有空要实现一个通知中心,让自己理解更深刻一些。& & KVO也是一种观察者模式,KVO会自动给Subject类创建一个子类,然后将Subject类的isa指针指向派生类.在派生类内部添加通知观察者的代码,需要使用setValueForKeypath的方式,因为这种方式的派生类内部才添加了notifyObserver的方法。添加属性观察的Subject需要调用addObserver方法来添加观察者,当属性改变,观察者的ObserverForKeyPath会呗调用。这个有空也实现一个,应该不算复杂,主要是内部机制自己理解还不是很透彻。MVC模式& & Cocoa中的MVC的模型和视图没有任何交互,全是通过中间人ViewController交互的。& & ViewController持有很多View的对象指针(IBOutlet),因此可以直接操纵view,view可以通过委托和协议的机制将操作反馈给ViewController,还有button的回调(IBAction)也可以反馈到Controller。& & Controller也一般持有model的指针,可以直接更新model数据;model数据可以使用Notification和KVO机制将model的更改通知给Controller。上面的这几个策略基本上概括了整个MVC的东西,斯坦福公开课有一个图片很好,大家值得一看。& & & & OK,就到这里吧,得回家了,太晚了,明天继续写。
声明:该文章系网友上传分享,此内容仅代表网友个人经验或观点,不代表本网站立场和观点;若未进行原创声明,则表明该文章系转载自互联网;若该文章内容涉嫌侵权,请及时向上学吧网站投诉>>
上一篇:下一篇:
相关经验教程
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.003 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.005 收益
的原创经验被浏览,获得 ¥0.001 收益
的原创经验被浏览,获得 ¥0.005 收益& & 前言:& & 学完了底层c,c++之后,现在开始重新回头进行上层的界面设计。既然做了就要做好,就如同过去c,c++做的一样。过去的一年的时间精看了深入浅出mfc,C++程序设计语言,effective-c++,GOF和大话设计模式,粗看了more effective c++, c++ premier,linux程序设计,harly guide linux, 自觉在c++方面的战果还算不错,现在重新捡起刚从事半年多的ios,一方面是因为money,另一方面是因为过去确实底层能力不行,对于界面处于知其然而不知其所以然的状态,现在重新看起,书籍一定是必需品了。买了两本书,ios开发指南和ios设计模式解析。这一段博客主要记录书籍的学习过程,还有过去的未竟的任务,将好的思想,好的策略浓缩一下便于为我所用。ios开发指南& & 国人写的书,一直对国人的技术书籍有种抵触情绪,不过看这本书的目录结构比较适合我,于是放弃了精通ios开发那本而选择了这本。这本书有点太厚了,接近700页,拿在手上不适合,太重,讲的东西多,但是不算杂,各项均有涉及,有个别错误,内容不算高深,适合我这样的小半桶水看。ios设计模式解析是没有时间看了,先让它睡着吧,把基本的捡起来以便于自己好迅速的上手公司的代码,要不然以后工作有我受的了。第一章& & xcode简介,书籍图片,内容介绍,书中源码链接。没啥有太大意义的内容。第二章& & 应用程序的生命周期值得读一读。& & 打开程序: Not Run (applicationDidFinishLauch) ->InActive (ApplicationDidBecomeActive)->Active& & 程序后台:
Active (applicationWillResignActive) ->InActive ->Backgroud (applicationDidEnterBackgroud)->Suspend (applciationWillTerminate) ->Terminate& & 挂起运行:
Suspend ->Backgroud (applciationWillEnterForgroud) ->InActive (applicationWillBecomeActive) ->Active& & 当系统内存不足的时候,后台的Suspend程序有可能会被系统kill掉,没有通知。& & 视图的生命周期& & loadView(得到一个view) ->ViewDidLoad(在生成的view后添加subview以进行自我的定制) ->ViewWillAppear ->viewWillDisappear ->didReceiveMemoryWarnning (收到内存警告) ->viewDidUnLoad& & loadView是为了创建self.view,当从nib文件中去加载就会直接创建self.view,因此loadView也就不需要了。& & Xcode的project和target& & 一个project对应这多个target,project的设置是公共的,target的设置可以覆盖project的设置。在target的summary选项下,设置屏幕图标57*57, Icon.png,retina屏幕为Icon@2x.png, 启动屏幕为320*480,Default.png或者retina屏幕为Default@2x.png, 设备支持选项。& & ios Api简介& & 框架太多,不容易记忆,再说必要性不是很大。注意大的有四个层次: Cocoa Touch,
Core Services, Core OS。具体的每一个层次包含什么,暂时不关心。还有如何使用帮助文档,alt+鼠标点击-》打开帮助文档第三章 基本的设计模式& & ios常用设计模式,这个我比较擅长,相对就简单多了。单例模式& & 没有使用synchronized机制,使用gcd的一种dispatch_once机制来维护仅仅执行一次的操作,比加锁效率高一些,至于内部原理,暂时不懂,不过以后会搞定它的底层的。来个简单代码示例便于以后copy& & @interface Singleton : NSObject& & @end& & @implementation Singleton& & static Singleton *_shareSingleton =& & + (Singleton*) sharedManager& & {& & static dispatch_once_& & dispatch_once(&once, ^{& & _shareSingleton = [[Singleton alloc]init];& & //...... your other initial code here& & }& & );& & return _shareS& & }& & 思想很简单,私有静态指针,类方法中分配内存并返回这个指针。为了防止多线程同时访问可能会创建几个对象,可以采用加锁,为了提高效率,有一种二次探测的策略;这里采用的GCD的内容保证只执行一次。& & 示例: UIAccelerometer NSUserDefault NSNotificationCenter等等。委托模式& & 我比较挠头的一种模式,说起来就是我定义了一个框架,但是又想给使用者以个性化的操作,于是将个性化的操作提取出来,制作成协议,让客户去实现协议。举个UITableView的例子, ViewController实现UITableViewDelegate协议, viewController持有一个UItableView的指针,设置tableView.delegate = self。这样tableView相当于将个性化的操纵留给了ViewController去完成了。& & 简单类图:& & UITableViewDelegate& & |& & |& & UITableView (持有delegate指针)------------->MyViewController(持有tableView指针,并设置delegate)& & MyViewController继承delegate同时持有tableView的指针,这个是一个强引用。UITableView也持有一个delegate指针,由于这个指针最终要赋值为MyViewController对象,因此为了避免循环引用,一定是一个弱引用。一般是在MyViewControlller中设置tableView.delegate为自身,也就是说MyViewController负责实现delegate方法。这样UITableView自身实现了TableView的基本框架,同时将用户的个性化的可扩展的地方弄成协议供客户实现。协议的调用肯定是UITableView内部框架去做的,它需要数据的时候就去协议要数据,协议呢给用户以最大的扩展性,同时用户有不用关心UITableView具体的内部是如何呈现了,用户只需要提供数据就行了。示例 UITextField Application观察者模式& & 相当简单的一种设计模式,但是又相当常用。一定要记住一个Subject,n多个Observer。Subject需要实现addObserver,removeObserver,notifyAllObservers的方法,同时有一个observers数组保存所有的observer;observer需要实现update方法。当需要更新数据的时候,调用notifyAllObservers方法,这个方法中遍历数组的所有observer,调用observer的update方法去更新数据。通知中心就是一个subject,为了方便使用它以单例模式实现的,后面有空要实现一个通知中心,让自己理解更深刻一些。& & KVO也是一种观察者模式,KVO会自动给Subject类创建一个子类,然后将Subject类的isa指针指向派生类.在派生类内部添加通知观察者的代码,需要使用setValueForKeypath的方式,因为这种方式的派生类内部才添加了notifyObserver的方法。添加属性观察的Subject需要调用addObserver方法来添加观察者,当属性改变,观察者的ObserverForKeyPath会呗调用。这个有空也实现一个,应该不算复杂,主要是内部机制自己理解还不是很透彻。MVC模式& & Cocoa中的MVC的模型和视图没有任何交互,全是通过中间人ViewController交互的。& & ViewController持有很多View的对象指针(IBOutlet),因此可以直接操纵view,view可以通过委托和协议的机制将操作反馈给ViewController,还有button的回调(IBAction)也可以反馈到Controller。& & Controller也一般持有model的指针,可以直接更新model数据;model数据可以使用Notification和KVO机制将model的更改通知给Controller。上面的这几个策略基本上概括了整个MVC的东西,斯坦福公开课有一个图片很好,大家值得一看。& & & & OK,就到这里吧,得回家了,太晚了,明天继续写。
您对本文章有什么意见或着疑问吗?请到您的关注和建议是我们前行的参考和动力&&UIKit&Dynamics入门,用于实现复杂UI动画
本文涉及到的WWDC2013 Session有
Session 206 Getting Started
with UIKit Dynamics
Session 221 Advanced
Techniques with UIKit Dynamics
什么是UIKit动力学(UIKit Dynamics)
其实就是UIKit的一套动画和交互体系。我们现在进行UI动画基本都是使用CoreAnimation或者UIView
animations。而UIKit动力学最大的特点是将现实世界动力驱动的动画引入了UIKit,比如重力,铰链连接,碰撞,悬挂等效果。一言蔽之,即是,将2D物理引擎引入了人UIKit。需要注意,UIKit动力学的引入,并不是以替代CA或者UIView动画为目的的,在绝大多数情况下CA或者UIView动画仍然是最优方案,只有在需要引入逼真的交互设计的时候,才需要使用UIKit动力学它是作为现有交互设计和实现的一种补充而存在的。
目的当然是更加自然和炫目的UI动画效果,比如模拟现实的拖拽和弹性效果,放在以前如果单用iOS
SDK的动画实现起来还是相当困难的,而在UIKit
Dynamics的帮助下,复杂的动画效果可能也只需要很短的代码(基本100行以内…其实现在用UIView
animation想实现一个不太复杂的动画所要的代码行数都不止这个数了吧)。总之,便利多多,配合UI交互设计,以前很多不敢想和不敢写(至少不敢自己写)的效果实现起来会非常方便,也相信在iOS7的时代各色使用UIKit动力学的应用的在动画效果肯定会上升一个档次。
那么,应该怎么做呢
UIKit动力学实现的结构
为了实现动力UI,需要注册一套UI行为的体系,之后UI便会按照预先的设定进行运动了。我们应该了解的新的基本概念有如下四个:
UIDynamicItem:用来描述一个力学物体的状态,其实就是实现了UIDynamicItem委托的对象,或者抽象为有面积有旋转的质点;
UIDynamicBehavior:动力行为的描述,用来指定UIDynamicItem应该如何运动,即定义适用的物理规则。一般我们使用这个类的子类对象来对一组UIDynamicItem应该遵守的行为规则进行描述;
UIDynamicAnimator;动画的播放者,动力行为(UIDynamicBehavior)的容器,添加到容器内的行为将发挥作用;
ReferenceView:等同于力学参考系,如果你的初中物理不是语文老师教的话,我想你知道这是啥..只有当想要添加力学的UIView是ReferenceView的子view时,动力UI才发生作用。
光说不练假把式,来做点简单的demo吧。比如为一个view添加重力行为:
- (void)viewDidLoad
[super viewDidLoad];
UIView *aView = [[UIView alloc] initWithFrame:CGRectMake(100, 50, 100, 100)];
aView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:aView];
UIDynamicAnimator* animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UIGravityBehavior* gravityBeahvior = [[UIGravityBehavior alloc] initWithItems:@[aView]];
[animator addBehavior:gravityBeahvior];
self.animator = animator;
代码很简单,
以现在ViewController的view为参照系(ReferenceView),来初始化一个UIDynamicAnimator。
然后分配并初始化一个动力行为,这里是UIGravityBehavior,将需要进行物理模拟的UIDynamicItem传入。UIGravityBehavior的initWithItems:接受的参数为包含id的数组,另外UIGravityBehavior实例还有一个addItem:方法接受单个的id。就是说,实现了UIDynamicItem委托的对象,都可以看作是被力学特性影响的,进而参与到计算中。UIDynamicItem委托需要我们实现bounds,center和transform三个属性,在UIKit
Dynamics计算新的位置时,需要向Behavior内的item询问这些参数,以进行正确计算。iOS7中,UIView和UICollectionViewLayoutAttributes已经默认实现了这个接口,所以这里我们直接把需要模拟重力的UIView添加到UIGravityBehavior里就行了。
把配置好的UIGravityBehavior添加到animator中。
strong持有一下animator,避免当前scope结束被ARC释放掉(后果当然就是UIView在哪儿傻站着不掉)
运行结果,view开始受重力影响了:
重力作用下的UIview
碰撞,我要碰撞
没有碰撞的话,物理引擎就没有任何意义了。和重力行为类似,碰撞也有一个UIDynamicBehavior子类来描述碰撞行为,即UICollisionBehavior。在上面的demo中加上几句:
- (void)viewDidLoad
[super viewDidLoad];
UIView *aView = [[UIView alloc] initWithFrame:CGRectMake(100, 50, 100, 100)];
aView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:aView];
UIDynamicAnimator* animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UIGravityBehavior* gravityBeahvior = [[UIGravityBehavior alloc] initWithItems:@[aView]];
[animator addBehavior:gravityBeahvior];
UICollisionBehavior* collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[aView]];
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
[animator addBehavior:collisionBehavior];
collisionBehavior.collisionDelegate = self;
self.animator = animator;
也许聪明的你已经看到了,还是一样的,创建新的行为规则(UICollisionBehavior),然后加到animator中…唯一区别的地方是碰撞需要设定碰撞边界范围translatesReferenceBoundsIntoBoundary将整个参照view(也就是self.view)的边框作为碰撞边界(另外你还可以使用setTranslatesReferenceBoundsIntoBoundaryWithInsets:这样的方法来设定某一个区域作为碰撞边界,更复杂的边界可以使用addBoundaryWithIdentifier:forPath:来添加UIBezierPath,或者addBoundaryWithIdentifier:fromPoint:toPoint:来添加一条线段为边界,详细地还请查阅文档);另外碰撞是有回调的,可以在self中实现UICollisionBehaviorDelegate。
最后,只是直直地掉下来的话未免太无聊了,加个角度吧:
aView.transform = CGAffineTransformRotate(aView.transform, 45);
结果是这样的,帅死了…这在以前只用iOS SDK的话,够写上很长时间了吧..
碰撞和重力同时作用的动力UI
碰撞的delegate可以帮助我们了解碰撞的具体情况,包括哪个item和哪个item开始发生碰撞,碰撞接触点是什么,是否和边界碰撞,和哪个边界碰撞了等信息。这些回调方法保持了Apple一向的命名原则,所以通俗易懂。需要多说一句的是回调方法中对于ReferenceView的Bounds做边界的情况,BoundaryIdentifier将会是nil,自行添加的其他边界的话,ID自然是添加时指定的ID了。
collisionBehavior:beganContactForItem:withBoundaryIdentifier:atPoint:
collisionBehavior:beganContactForItem:withItem:atPoint:
collisionBehavior:endedContactForItem:withBoundaryIdentifier:
collisionBehavior:endedContactForItem:withItem:
其他能实现的效果
除了重力和碰撞,iOS SDK还预先帮我们实现了一些其他的有用的物理行为,它们包括
UIAttachmentBehavior
描述一个view和一个锚相连接的情况,也可以描述view和view之间的连接。attachment描述的是两个点之间的连接情况,可以通过设置来模拟无形变或者弹性形变的情况(再次希望你还记得这些概念,简单说就是木棒连接和弹簧连接两个物体)。当然,在多个物体间设定多个;UIAttachmentBehavior,就可以模拟多物体连接了..有了这些,似乎可以做个老鹰捉小鸡的游戏了-
UISnapBehavior
将UIView通过动画吸附到某个点上。初始化的时候设定一下UISnapBehavior的initWithItem:snapToPoint:就行,因为API非常简单,视觉效果也很棒,估计它是今后非游戏app里会被最常用的效果之一了;
UIPushBehavior
可以为一个UIView施加一个力的作用,这个力可以是持续的,也可以只是一个冲量。当然我们可以指定力的大小,方向和作用点等等信息。
UIDynamicItemBehavior
其实是一个辅助的行为,用来在item层级设定一些参数,比如item的摩擦,阻力,角阻力,弹性密度和可允许的旋转等等
UIDynamicItemBehavior有一组系统定义的默认值,
allowsRotation YES
density 1.0
elasticity 0.0
friction 0.0
resistance 0.0
所有的UIDynamicBehavior都是可以独立作用的,同时作用时也遵守力的合成。也就是说,组合使用行为可以达到一些较复杂的效果。举个例子,希望模拟一个drag物体然后drop后下落的过程,可以用如下代码:
- (void)viewDidLoad
[super viewDidLoad];
UIDynamicAnimator* animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UICollisionBehavior* collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[self.square1]];
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
[animator addBehavior:collisionBehavior];
UIGravityBehavior *g = [[UIGravityBehavior alloc] initWithItems:@[self.square1]];
[animator addBehavior:g];
self.animator = animator;
-(IBAction)handleAttachmentGesture:(UIPanGestureRecognizer*)gesture
if (gesture.state == UIGestureRecognizerStateBegan){
CGPoint squareCenterPoint = CGPointMake(self.square1.center.x, self.square1.center.y - 100.0);
UIAttachmentBehavior* attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:self.square1 attachedToAnchor:squareCenterPoint];
self.attachmentBehavior = attachmentBehavior;
[self.animator addBehavior:attachmentBehavior];
} else if ( gesture.state == UIGestureRecognizerStateChanged) {
[self.attachmentBehavior setAnchorPoint:[gesture locationInView:self.view]];
} else if (gesture.state == UIGestureRecognizerStateEnded) {
[self.animator removeBehavior:self.attachmentBehavior];
viewDidiLoad时先在现在环境中加入了重力,然后监测到pan时附加一个UIAttachmentBehavior,并在pan位置更新更新其锚点,此时UIAttachmentBehavior和UIGravityBehavior将同时作用(想象成一根木棒连着手指处和view)。在手势结束时将这个UIAttachmentBehavior移除,view将在重力作用下下落。整个过程如下图:
UIKit力学的物理学分析
既然是力学,那显然各种单位是很重要的。在现实世界中,理想情况下物体的运动符合牛顿第二运动定理,在国际单位制中,力的单位是牛顿(N),距离单位是米(m),时间单位是秒(s),质量单位是千克(kg)。根据地球妈妈的心情,我们生活在这样一套体制中:重力加速度约为9.8m/s2&,加速度的单位是m/s2&,速度单位是m/s,牛顿其实是kg·m/s2&,即1牛顿是让质量为1千克的物体产生1米每二次方秒的加速度所需要的力。
以上是帮助您回忆初中知识,而现在这一套体系在UIKit里又怎么样呢?这其实是每一个物理引擎都要讨论和明白的事情,UIKit的单位体制里由于m这个东西太过夸张,因此用等量化的点(point,之后简写为p)来代替。具体是这样的:UI重力加速度定义为1000p/s2&,这样的定义有两方面的考虑,一时为了简化,好记,确实来的只观好看,二是也算符合人们的直感:一个UIView从y=0开始自由落体落到屏幕底部所需的时间,在3.5寸屏幕上为0.98秒,4寸屏幕上为1.07秒,1秒左右的自由落体的视觉效果对人眼来说是很舒服能进行判断的。
那么UIView的质量又如何定义呢,这也是很重要的,并涉及到力作用和加速度下UIView的表现。苹果又给出了自己的“UIKit牛顿第二定律”,定义了1单位作用力相当于将一个100px100p的默认密度的UIView以100p/s2&的加速度移动。这里需要注意默认密度这个假设,因为在UIDynamicItem的委托中并没有实现任何密度相关的定义,而是通过UIDynamicItemBehavior来附加指定的。默认情况下,密度值为1,这就相当于质量是10000单位的UIView在1单位的作用力下可以达到1/10的UI重力加速度。
这样类比之后的结论是,如果将1单位的UI力学中的力等同于1牛顿的话:
1000单位的UI质量,与现实世界中1kg的质量相当,即一个点等同一克;
屏幕的100像素的长度,约和现实世界中0.99米相当(完全可以看为1米)
UI力学中的默认密度,约和现实世界的0.1kg/m2&相当
可以说UIKit为我们构建了一套适应iOS屏幕的相当优雅的力学系统,不仅让人过目不忘,在实际的物理情景和用户体验中也近乎完美。在开发中,我们可以参照这些关系寻找现实中的例子,然后将其带入UIKit的力学系统中,以得到良好的模拟效果。
UIKit动力学自定义
除了SDK预先定义好的行为以外,我们还可以自己定义想要的行为。这种定义可以发生在两个层级上,一种是将官方的行为打包,以简化实现。另一种是完全定义新的计算规则。
对于第一种,其实考虑一下上面的重力+边界碰撞,或者drag &
drop行为,其实都是两个甚至多个行为的叠加。要是每次都这样设定一次的话,不是很辛苦么,还容易遗忘出错。于是一种好的方式是将它们打包封装一下。具体地,如下步骤:
继承一下UIDynamicBehavior(在这里UIDynamicBehavior类似一个抽象类,并没有具体实现什么行为)
在子类中实现一个类似其他内置行为初始化方法initWithItems:,用以添加物体和想要打包的规则。当然你如果喜欢用其他方式也行..只不过和自带的行为保持API统一对大家都有好处..添加item的话就用默认规则的initWithItems:就行,对于规则UIDynamicBehavior提供了一个addChildBehavior:的方法,来将其他规则加入到当前规则里
没有第三步了,使用就行了。
一个例子,打包了碰撞和重力两种行为,定义之后使用时就只需要写一次了。当然这只是最简单的例子和运用,当行为复杂以后,这样的使用方法是不可避免的,否则管理起来会让人有想死的心。另外,将手势等交互的方式也集成之中,进一步封装调用细节会是不错的实践。
//GravityWithCollisionBehavior.h
@interface GravityWithCollisionBehavior : UIDynamicBehavior
-(instancetype) initWithItems:(NSArray *)items;
//GravityWithCollisionBehavior.m
@implementation GravityWithCollisionBehavior
-(instancetype) initWithItems:(NSArray *)items
if (self = [super init]) {
UIGravityBehavior *gb = [[UIGravityBehavior alloc] initWithItems:items];
UICollisionBehavior *cb = [[UICollisionBehavior alloc] initWithItems:items];
cb.translatesReferenceBoundsIntoBoundary = YES;
[self addChildBehavior:gb];
[self addChildBehavior:cb];
return self;
另一种比较高级一点,需要对计算完全定义。在默认的行为或者它们组合不能满足禽兽般的产品经理/设计师的需求是,亲爱的骚年..开始自己写吧..其实说简单也简单,UIDynamicBehavior里提供了一个@property(nonatomic,
copy) void (^action)(void),animator将在每次animation
step(就是需要计算动画时)调用这个block。就是说,你可以通过设定这个block来实现自己的行为。基本思路就是在这个block中向所有item询问它们当前的center和transform状态,然后开始计算,然后把计算后的相应值再赋予item,从而改变在屏幕上的位置,大小,角度等。
UIKit动力学的性能分析和限制
使用物理引擎不是没有代价的的,特别是在碰撞检测这块,是要耗费一定CPU资源的。但是以测试的情况来看,如果只是UI层面上的碰撞检测还是没有什么问题的,我自己实测iPhone4上同时进行数十个碰撞计算完全没有掉帧的情况。因此如果只是把其用在UI特效上,应该不用太在意资源的耗费。但是如果同时有成百上千的碰撞需要处理的情况,可能会出现卡顿吧。
对于UIDynamicItem来说,当它们被添加到动画系统后,我们只能通过动画系统来改变位置,而外部的对于UIDynamicItem的center,transform等设定是被忽略的(其实这也是大多数2D引擎的实现策略,算不上限制)。
主要的限制是在当计算迭代无法得到有效解的时候,动画将无法正确呈现。这对于绝大多数物理引擎都是一样的。迭代不能收敛时整个物理系统处于不确定的状态,比如初始时就设定了碰撞物体位于边界内部,或者在狭小空间内放入了过多的非弹性碰撞物体等。另外,这个引擎仅仅只是用来呈现UI效果,它并没有保证物理上的精确度,因此如果要用它来做UI以外的事情,有可能是无法得到很好的结果的。
总之就是一套全新的UI交互的视觉体验和效果,但是并非处处适用。在合适的地方使用可以增加体验,但是也会有其他方式更适合的情况。所以拉上你的设计师好基友去开拓新的大陆吧…
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 behavior可数吗 的文章

 

随机推荐