iOS开发概述UIkit动力学,讲述UIKit的Dynamic特性,UIkit动力学是UIkit框架中模拟真实世界的一些特性。
目录[-]
由于博客迁移至www.coderyi.com,文章请看http://www.coderyi.com/archives/426
UIkit动力学是UIkit框架中模拟真实世界的一些特性。
UIDynamicAnimator
主要有UIDynamicAnimator类,通过这个类中的不同行为来实现一些动态特性。
它一般有两种初始化方法,先讲常见的第一种
|
1
|
animator= [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; |
动态特性的实现主要依靠它所添加的行为,通过以下方法进行添加和移除,
|
1
2
|
[animator addBehavior:attachmentBehavior]; [animator removeAllBehaviors]; |
接下来介绍五个不同的行为,UIAttachmentBehavior(吸附),UICollisionBehavior(碰撞),UIGravityBehavior(重力),UIPushBehavior(推动),UISnapBehavior(捕捉)。另外还有一个辅助的行为UIDynamicItemBehavior,用来在item层级设定一些参数,比如item的摩擦,阻力,角阻力,弹性密度和可允许的旋转等等。
UIAttachmentBehavior(吸附)
先讲吸附行为,
它的初始化方法
|
1
2
3
|
attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:iv offsetFromCenter:centerOffset attachedToAnchor:location]; |
item是实现UIDynamicItem协议的id类型,这里设置吸附一个UIImageView的实例iv。offset可以设置吸附的偏移,anchor是设置锚点。
UIAttachmentBehavior有几个属性,例如damping,frequency。damping是阻尼数值,frequency是震动频率
直接上代码,实现一个pan手势,让一个image跟着手势跑
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
-(void)gesture:(UIPanGestureRecognizer *)gesture{ CGPoint location = [gesture locationInView:self.view]; CGPoint boxLocation = [gesture locationInView:iv]; switch (gesture.state) { case UIGestureRecognizerStateBegan:{ NSLog(@"you touch started position %@",NSStringFromCGPoint(location)); NSLog(@"location in image started is %@",NSStringFromCGPoint(boxLocation)); [animator removeAllBehaviors]; // Create an attachment binding the anchor point (the finger's current location) // to a certain position on the view (the offset) UIOffset centerOffset = UIOffsetMake(boxLocation.x - CGRectGetMidX(iv.bounds), boxLocation.y - CGRectGetMidY(iv.bounds)); attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:iv offsetFromCenter:centerOffset attachedToAnchor:location]; attachmentBehavior.damping=0.5; attachmentBehavior.frequency=0.8; // Tell the animator to use this attachment behavior [animator addBehavior:attachmentBehavior]; break; } case UIGestureRecognizerStateEnded: { [animator removeBehavior:attachmentBehavior]; break; } default: [attachmentBehavior setAnchorPoint:[gesture locationInView:self.view]]; break; }} |
UIPushBehavior(推动)
UIPushBehavior 可以为一个UIView施加一个力的作用,这个力可以是持续的,也可以只是一个冲量。我们可以指定力的大小,方向和作用点等等信息。
|
1
2
3
|
pushBehavior = [[UIPushBehavior alloc] initWithItems:@[iv] mode:UIPushBehaviorModeInstantaneous]; |
UIPushBehavior 有pushDirection、magnitude等属性,
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
//1 CGPoint velocity = [gesture velocityInView:self.view]; CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y)); if (magnitude > ThrowingThreshold) { //2 pushBehavior = [[UIPushBehavior alloc] initWithItems:@[iv] mode:UIPushBehaviorModeInstantaneous]; pushBehavior.pushDirection = CGVectorMake((velocity.x / 10) , (velocity.y / 10)); pushBehavior.magnitude = magnitude / ThrowingvelocityPadding; [animator addBehavior:pushBehavior]; //3// UIDynamicItemBehavior 其实是一个辅助的行为,用来在item层级设定一些参数,比如item的摩擦,阻力,角阻力,弹性密度和可允许的旋转等等 NSInteger angle = arc4random_uniform(20) - 10; itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[iv]]; itemBehavior.friction = 0.2; itemBehavior.allowsRotation = YES; [itemBehavior addAngularVelocity:angle forItem:iv]; [animator addBehavior:itemBehavior]; //4 [self performSelector:@selector(resetDemo) withObject:nil afterDelay:0.4]; } |
UIGravityBehavior(重力)
直接上代码,实现随机掉落一张图片的代码
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
// Set up self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.gravityBeahvior = [[UIGravityBehavior alloc] initWithItems:nil]; [self.animator addBehavior:self.gravityBeahvior]; - (void)tapped:(UITapGestureRecognizer *)gesture { NSUInteger num = arc4random() % 40 + 1; NSString *filename = [NSString stringWithFormat:@"m%lu", (unsigned long)num]; UIImage *image = [UIImage imageNamed:filename]; UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; [self.view addSubview:imageView]; CGPoint tappedPos = [gesture locationInView:gesture.view]; imageView.center = tappedPos; [self.gravityBeahvior addItem:imageView]; } |
UICollisionBehavior(碰撞)
继续上面的代码,当图片快掉落出边界的时候有 碰撞效果,这个就是UICollisionBehavior实现的。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
// Set up self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.gravityBeahvior = [[UIGravityBehavior alloc] initWithItems:nil]; self.collisionBehavior = [[UICollisionBehavior alloc] initWithItems:nil]; self.collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; self.itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:nil]; self.itemBehavior.elasticity = 0.6; self.itemBehavior.friction = 0.5; self.itemBehavior.resistance = 0.5; [self.animator addBehavior:self.gravityBeahvior]; [self.animator addBehavior:self.collisionBehavior]; [self.animator addBehavior:self.itemBehavior]; - (void)tapped:(UITapGestureRecognizer *)gesture { NSUInteger num = arc4random() % 40 + 1; NSString *filename = [NSString stringWithFormat:@"m%lu", (unsigned long)num]; UIImage *image = [UIImage imageNamed:filename]; UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; [self.view addSubview:imageView]; CGPoint tappedPos = [gesture locationInView:gesture.view]; imageView.center = tappedPos; [self.gravityBeahvior addItem:imageView]; [self.collisionBehavior addItem:imageView]; [self.itemBehavior addItem:imageView];} |
另外,UICollisionBehavior有它的代理,其中列举两个方法,它们表示行为开始和结束的时候的代理。
|
1
2
|
- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier atPoint:(CGPoint)p;- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier; |
UISnapBehavior(捕捉)
UISnapBehavior 将UIView通过动画吸附到某个点上。
|
1
2
3
4
5
6
7
8
9
10
|
- (void) handleTap:(UITapGestureRecognizer *)paramTap{ CGPoint tapPoint = [paramTap locationInView:self.view]; if (self.snapBehavior != nil){ [self.animator removeBehavior:self.snapBehavior]; } self.snapBehavior = [[UISnapBehavior alloc] initWithItem:self.squareView snapToPoint:tapPoint]; self.snapBehavior.damping = 0.5f; //剧列程度 [self.animator addBehavior:self.snapBehavior];} |
UICollectionView与UIDynamicAnimator
文章开头说到UIDynamicAnimator有两种初始化方法,这里介绍它与UICollectionView的完美结合,让UICollectionView产生各种动态特性的行为。
你是否记得iOS系统中信息应用中的附有弹性的消息列表,他就是加入了UIAttachmentBehavior吸附行为,这里通过一个UICollectionView实现类似效果。
主要是复写UICollectionViewFlowLayout,在layout中为每一个布局属性元素加上吸附行为就可以了。
关于复写layout,可以参考onevcat的博客
http://www.onevcat.com/2012/08/advanced-collection-view/
下面就直接上代码了
首先遍历每个 collection view layout attribute 来创建和添加新的 dynamic animator
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
-(void)prepareLayout { [super prepareLayout]; if (!_animator) { _animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self]; CGSize contentSize = [self collectionViewContentSize]; NSArray *items = [super layoutAttributesForElementsInRect:CGRectMake(0, 0, contentSize.width, contentSize.height)]; for (UICollectionViewLayoutAttributes *item in items) { UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:item attachedToAnchor:item.center]; attachment.length = 0; attachment.damping = self.damping; attachment.frequency = self.frequency; [_animator addBehavior:attachment]; } }} |
接下来我们现在需要实现 layoutAttributesForElementsInRect: 和 layoutAttributesForItemAtIndexPath: 这两个方法,UIKit 会调用它们来询问 collection view 每一个 item 的布局信息。我们写的代码会把这些查询交给专门做这些事的 dynamic animator
|
1
2
3
4
5
6
7
|
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { return [_animator itemsInRect:rect];} - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { return [_animator layoutAttributesForCellAtIndexPath:indexPath];} |
然后是响应滚动事件的方法
这个方法会在 collection view 的 bound 发生改变的时候被调用,根据最新的 content offset 调整我们的 dynamic animator 中的 behaviors 的参数。在重新调整这些 behavior 的 item 之后,我们在这个方法中返回 NO;因为 dynamic animator 会关心 layout 的无效问题,所以在这种情况下,它不需要去主动使其无效
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = self.collectionView; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; NSLog(@" %f %f",newBounds.origin.y,scrollView.bounds.origin.y); CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *behavior in _animator.behaviors) { CGPoint anchorPoint = behavior.anchorPoint; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / self.resistanceFactor; UICollectionViewLayoutAttributes *item = [behavior.items firstObject]; CGPoint center = item.center; center.y += (scrollDelta > 0) ? MIN(scrollDelta, scrollDelta * scrollResistance) : MAX(scrollDelta, scrollDelta * scrollResistance); item.center = center; [_animator updateItemUsingCurrentState:item]; } return NO;} |
让我们仔细查看这个代码的细节。首先我们得到了这个 scroll view(就是我们的 collection view ),然后计算它的 content offset 中 y 的变化(在这个例子中,我们的 collection view 是垂直滑动的)。一旦我们得到这个增量,我们需要得到用户接触的位置。这是非常重要的,因为我们希望离接触位置比较近的那些物体能移动地更迅速些,而离接触位置比较远的那些物体则应该滞后些。
对于 dynamic animator 中的每个 behavior,我们将接触点到该 behavior 物体的 y 的距离除以 500。分母越小,这个 collection view 的的交互就越有弹簧的感觉。
iOS开发概述UIkit动力学,讲述UIKit的Dynamic特性,UIkit动力学是UIkit框架中模拟真实世界的一些特性。的更多相关文章
- XE6 & IOS开发之开发者账号、苹果证书(3):关于在XE6中使用苹果证书的简单介绍
网上能找到的关于Delphi XE系列的移动开发的相关文章甚少,本文尽量以详细的图文内容.傻瓜式的表达来告诉你想要的答案. 原创作品,请尊重作者劳动成果,转载请注明出处!!! 1.关于在XE6中使用苹 ...
- iOS开发——UI进阶篇(十三)UITabBarController简单使用,qq主流框架
一.UITabBarController简单使用 // 程序加载完毕 - (BOOL)application:(UIApplication *)application didFinishLaunchi ...
- iOS开发——UI篇OC篇&UIDynamic详解
iOS开发拓展篇—UIDynamic(简单介绍) 一.简单介绍 1.什么是UIDynamic UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架 可以认为是一种物理引擎,能模拟 ...
- 从Swift学习iOS开发的路线指引
本文主要是楼主近段时间从Swift语法开始自学iOS开发的流程总结,PS 一个前提,楼主的生存环境中买不到一本iOS开发中文教程,所以基本都是百度摸索出来的 >_< 主要流程 学习Swif ...
- iOS开发之窥探UICollectionViewController(五) --一款炫酷的图片浏览组件
本篇博客应该算的上CollectionView的高级应用了,从iOS开发之窥探UICollectionViewController(一)到今天的(五),可谓是由浅入深的窥探了一下UICollectio ...
- ios开发介绍
iOS开发概述 •什么是IOS •什么是IOS开发 •为什么要选择IOS开发 •学习IOS开发的准备 1.什么是iOS •iOS是一款由苹果公司开发的操作系统(OS是Operating Sys ...
- IOS开发基础知识碎片-导航
1:IOS开发基础知识--碎片1 a:NSString与NSInteger的互换 b:Objective-c中集合里面不能存放基础类型,比如int string float等,只能把它们转化成对象才可 ...
- iOS开发 Xcode8中遇到的问题及改动
iOS开发 Xcode8中遇到的问题及改动 新版本发布总会有很多坑,也会有很多改动. 一个一个填吧... 一.遇到的问题 1.权限以及相关设置 iOS10系统下调用系统相册.相机功能,或者苹果健康 ...
- iOS开发进阶
<iOS开发进阶>基本信息作者: 唐巧 出版社:电子工业出版社ISBN:9787121247453上架时间:2014-12-26出版日期:2015 年1月开本:16开页码:268版次:1- ...
随机推荐
- C#中使用正则表达式提取超链接地址的集中方法
一般在做爬虫或者CMS的时候经常需要提取 href链接或者是src地址.此时可以使用正则表达式轻松完成. Regex reg = new Regex(@"(?is)<a[^>]* ...
- UVALive - 3942 Remember the Word
input 字符串s 1<=len(s)<=300000 n 1<=n<=4000 word1 word2 ... wordn 1<=len(wordi)<=10 ...
- 求N以内与N互质的数的和
题目连接 /* 求所有小于N且与N不互质的数的和. 若:gcd(n,m)=1,那么gcd(n,n-m)=1; sum(n)=phi(n)*n/2; //sum(n)为小于n的所有与n互质的数的和 // ...
- Linux学习 -- 服务管理
1 服务分类 服务管理内容 启动 自启动 查询已安装的服务 RPM包安装的服务 自启动的 chkconfig --list 2345中如果是启用,代表下次开机会自启动 正在运行的服务 p ...
- 2016中国大学生程序设计竞赛 - 网络选拔赛 1004 Danganronpa
Problem Description Chisa Yukizome works as a teacher in the school. She prepares many gifts, which ...
- Discuz登录慢、退出也慢的原因?
Discuz登录慢.退出也慢的原因? 2009-02-21 12:50:11 分类: 转载自:http://www.aiseminar.cn/bbs/thread-201-1-1.html 由于服务 ...
- PAT1015
A reversible prime in any number system is a prime whose "reverse" in that number system i ...
- ADB shell出现error:device offline提示
解决办法: 1.adb kill-server 2.adb start-server 3.adb remount执行这3个命令然后重新键入adb shell应该就可以了
- redmine配置邮件
作为一个项目管理平台,必须能够通知项目成员有关项目和任务的各种状态变化.这也是一种典型的观察者模式.开发人员可以跟踪某个任务,当任务状态.备注.文档.优先级等变化时开发人员就可以得到通知. 对于新配置 ...
- Super Mario
Super Mario Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit ...