UIKit Dynamics归纳与实践

UIKit Dynamics 在 iOS 7 中首次被引入,可以让开发者通过简单的方式,给应用上的界面添加模拟物理世界的交互动画,用于改善用户体验。
在iOS 9中又加入了一些大的改进,在iOS 9之前,UIKitDynamics 的 collision bounds只能是长方形。这让一些并非是完美的长方形的碰撞效果看起来有些古怪。iOS 9 中支持三种 collision bounds分别是Rectangle(长方形),Ellipse(椭圆形)Path(路径)。Path 可以是任意路径,只要是逆时针的,并且不是交叉在一起的。一个警告是,path 必须是凸面的不能使凹面的,当然也可以自定义视图。讲完了常识,有了一个概念后开始干货讲解一下属性以及用法吧。

UIDynamicAnimator

UIDynamicAnimator用于创建力学动画生成器,封装了底下的物理引擎,使得我们可以方便地添加物理行为。

// 行为视图的父视图必须是动画生成器的参考视图
UIDynamicAnimator * animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];

UIDynamicAnimator包含了下面几种物理动画:
1、UIGravityBehavior(重力)
2、UICollisionBehavior(碰撞)
3、UIAttachmentBehavior(吸附)
4、UISnapBehavior (捕获)
5、UIPushBehavior(作用力)
另外UIDynamicBehavior 定义了物理行为的类型(例如:UIGravityBehavior等行为),UIDynamicItem 参与物理动画的对象。具体的下面开始讲解:

UIGravityBehavior——重力

创建UIGravityBehavior,并添加到UIDynamicBehavior,代码如下:

UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[label]];
[animator addBehavior:gravityBehavior];

上面是简单的动力的创建,Items指需要添加重力动画的对象。当然,还可以设置重力的方向以及作用力(也就是重力加速度,1.0为地球的重力加速度)

// 设置方向(dx,dy)
gravityBehavior.gravityDirection = CGVectorMake(0, 1.0);
// 设置angle:角度(弧度)  magnitude:量级(重力系数)
// 当然弧度以及重力系数都可以单独设置
[gravityBehavior setAngle:3.14/2 magnitude:0.1f];

magnitude重力系数:取值在0.0 - 1.0之间,1.0为地球引力,UIGravityBehavior就简单的介绍到这边。

UICollisionBehavior——碰撞

创建UICollisionBehavior,并添加到UIDynamicBehavior,代码如下:

 UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[label]];
[animator addBehavior:collisionBehavior];

iOS提供了对UICollisionBehavior的封装包括:碰撞模式、设置边界以及UICollisionBehaviorDelegate代理

模式
typedef NS_OPTIONS(NSUInteger, UICollisionBehaviorMode) {
    UICollisionBehaviorModeItems        = 1 << 0,//物体相互碰撞
    UICollisionBehaviorModeBoundaries   = 1 << 1,//物体不相互碰撞,只与边界碰撞
    UICollisionBehaviorModeEverything   = NSUIntegerMax//既与物体碰撞又与边界碰撞
} NS_ENUM_AVAILABLE_IOS(7_0);
边界
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
代理

UICollisionBehaviorDelegate提供了几种方法:

// 开始碰撞
- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(nullable id <NSCopying>)identifier atPoint:(CGPoint)p;
// 碰撞结束
- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(nullable id <NSCopying>)identifier;

UICollisionBehavior碰撞的介绍就到这了哈,具体使用还要看情景。

UIAttachmentBehavior——吸附

创建,并添加到引擎上:

UIAttachmentBehavior * attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:connectLabel attachedToAnchor:centerLabel.center];
[animator addBehavior:attachmentBehavior];

系统提供的构造初始化方法有以下几种:

  // 元素和锚点之间的吸附
- (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point;

// 元素和锚点之间的吸附,offset参数设置元素连接力作用点的偏移量
- (instancetype)initWithItem:(id <UIDynamicItem>)item offsetFromCenter:(UIOffset)offset attachedToAnchor:(CGPoint)point NS_DESIGNATED_INITIALIZER; 

// 元素和元素之间的吸附
- (instancetype)initWithItem:(id <UIDynamicItem>)item1 attachedToItem:(id <UIDynamicItem>)item2; 

// 元素和元素之间的吸附,offset1、offset2分别是两个元素连接力作用点的偏移量
- (instancetype)initWithItem:(id <UIDynamicItem>)item1 offsetFromCenter:(UIOffset)offset1 attachedToItem:(id <UIDynamicItem>)item2 offsetFromCenter:(UIOffset)offset2 NS_DESIGNATED_INITIALIZER;

属性

类型
typedef NS_ENUM(NSInteger, UIAttachmentBehaviorType) {
    UIAttachmentBehaviorTypeItems,  //吸附元素
    UIAttachmentBehaviorTypeAnchor  //吸附锚点
} NS_ENUM_AVAILABLE_IOS(7_0);

根据不同需求,针对是需要吸附元素Items还是锚点Anchor进行处理动画。

锚点
@property (readwrite, nonatomic) CGPoint anchorPoint;

当吸附发生在元素和锚点之间的时候,我们可以通过anchorPoint属性获得锚点位置,如果吸附发生在元素和元素之间的时候,该属性的值为(0, 0)

距离

元素吸附力作用点和锚点的距离 或 两个元素吸附力作用点间的距离

@property (readwrite, nonatomic) CGFloat length;
振动频率
@property (readwrite, nonatomic) CGFloat frequency; // in Hertz

frequency是指元素在发生弹性吸附时震动的频率,值越大,弹性运动的频率越快。

弹性阻力
@property (readwrite, nonatomic) CGFloat damping; // 1: critical damping

damping是设置元素在弹性吸附时震动所受到的阻力,值越大,阻力越大,弹性运动震动的幅度越小。

旋转阻力
@property (readwrite, nonatomic) CGFloat frictionTorque NS_AVAILABLE_IOS(9_0); // default is 0.0

frictionTorque为旋转力矩,指围绕一点旋转所受的阻力,默认值0.0,值越大,阻力越大。

运动范围
@property (readwrite, nonatomic) UIFloatRange attachmentRange NS_AVAILABLE_IOS(9_0); // default is UIFloatRangeInfinite

iOS 9新出的几个方法就不去说了,没用过哈,等后面去玩玩再来更新,当然有玩过的欢迎指教科普一下哈。

UISnapBehavior——捕获

创建UISnapBehavior

UISnapBehavior * snapBehavior = [[UISnapBehavior alloc] initWithItem:_dynamicItem1View snapToPoint:CGPointMake(250, 400)];
[animator addBehavior: snapBehavior];

Items参数为添加的动态元素,Point参数为要捕获的点。

属性

捕获点
@property (nonatomic, assign) CGPoint snapPoint NS_AVAILABLE_IOS(9_0);

在初始化方法中可以直接设置捕获点,当然也可以通过手势点击设置捕获点。

震动阻尼
@property (nonatomic, assign) CGFloat damping;

阻尼的有效范围为0.0~1.0,0.0最大震荡、1.0最小震荡,默认值为0.5

UIPushBehavior——作用力

给某物体加上一个作用力,让物体运动起来。

UIPushBehavior * pushBehavior = [[UIPushBehavior alloc] initWithItems:@[label] mode:UIPushBehaviorModeInstantaneous];
pushBehavior.pushDirection = CGVectorMake(1.0f, 0);
[animator addBehavior:pushBehavior];

属性

类型
typedef NS_ENUM(NSInteger, UIPushBehaviorMode) {
    UIPushBehaviorModeContinuous,        //连续作用力
    UIPushBehaviorModeInstantaneous    //瞬间作用力
} NS_ENUM_AVAILABLE_IOS(7_0);
活跃状态
@property (nonatomic, readwrite) BOOL active;

在添加一个push behavioranimator时,使用这个属性来激活或禁用推力作用,而不是通过重新添加behavior来实现。

推力角度
@property (readwrite, nonatomic) CGFloat angle;
推力矢量的大小
@property (readwrite, nonatomic) CGFloat magnitude;

默认值为nil,没有任何力量。当设置一个负值,力的方向改变。

推力矢量的方向
@property (readwrite, nonatomic) CGVector pushDirection;

方法

//  作用力中心偏移量设置
- (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item;

//  获取作用力中心偏移量
- (UIOffset)targetOffsetFromCenterForItem:(id <UIDynamicItem>)item;

//  设置推力的角度和大小
- (void)setAngle:(CGFloat)angle magnitude:(CGFloat)magnitude;

总结与问题

总体就先介绍这些吧,文章也比较长还没配图就凑合着看吧。本文还不够完善,给几个写的不错的链接吧@MajorLMJ,这位大神写的都很赞,他是把每一种类型单独区分开也配上了动画图,没办法公司的电脑配置跑不起模拟器手机录屏又麻烦就先不弄了哈,后续会更新。顺带附上一个对引擎应用的很赞的帖子仿饿了么店铺滚动,公司项目也有这个需求找了好久,后面又实践了下还是达不到饿了么或者美团外卖的效果,惭愧啊只做出一半的效果上滑的时候都没有问题但是在下拉回弹的时候达不到,当然还是会后续努力...废话就扯到这儿了。当然有实现出来的大牛欢迎给个demo给小弟研究研究或者指导一下也行,非常感谢哈。

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