ios UIKit动力 分类: ios技术 2015-07-14 12:55 196人阅读 评论(0) 收藏
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动力 分类: ios技术 2015-07-14 12:55 196人阅读 评论(0) 收藏的更多相关文章
- 利用OpenMP实现埃拉托斯特尼(Eratosthenes)素数筛法并行化 分类: 算法与数据结构 2015-05-09 12:24 157人阅读 评论(0) 收藏
1.算法简介 1.1筛法起源 筛法是一种简单检定素数的算法.据说是古希腊的埃拉托斯特尼(Eratosthenes,约公元前274-194年)发明的,又称埃拉托斯特尼筛法(sieve of Eratos ...
- 将HTML格式的String转化为HTMLElement 分类: C1_HTML/JS/JQUERY 2014-08-05 12:01 1217人阅读 评论(0) 收藏
代码如下: <meta charset="UTF-8"> <title>Insert title here</title> </head& ...
- Mahout快速入门教程 分类: B10_计算机基础 2015-03-07 16:20 508人阅读 评论(0) 收藏
Mahout 是一个很强大的数据挖掘工具,是一个分布式机器学习算法的集合,包括:被称为Taste的分布式协同过滤的实现.分类.聚类等.Mahout最大的优点就是基于hadoop实现,把很多以前运行于单 ...
- iOS开发之监听键盘高度的变化 分类: ios技术 2015-04-21 12:04 233人阅读 评论(0) 收藏
最近做的项目中,有一个类似微博中的评论转发功能,屏幕底端有一个输入框用textView来做,当textView成为第一响应者的时候它的Y值随着键盘高度的改变而改变,保证textView紧贴着键盘,但又 ...
- iOS搜索框UISearchBar 分类: ios技术 2015-04-03 08:55 82人阅读 评论(0) 收藏
当你在seachBar中输入字母之前的时候,只是用鼠标选中searchBar的时候,如图 终端输出截图如下:(这个时候调用先shouldBeginEditing,之后调用didBeginEditing ...
- C语言基础:函数指针 分类: iOS学习 c语言基础 2015-06-10 21:55 15人阅读 评论(0) 收藏
函数指针:指向函数的指针变量. 函数名相当于首地址. 函数指针定义:返回值类型 (*函数指针变量名)(参数类型1,参数类型2,....)=初始值 函数指针类型:返回值类型 (*)(参数类型1,参数 ...
- OC基础:NSString NSNumber 分类: ios学习 OC 2015-06-17 17:55 77人阅读 评论(0) 收藏
OC中的基本数据类型 NSString 在64位系统下,相当于long,在非64位系统下,想当于int. CGFloat 在64位系统下,相当于double,在非64位系统之下,想当与float ...
- OC基础:类和对象 分类: ios学习 OC 2015-06-12 18:55 17人阅读 评论(0) 收藏
OC:Objective-c 面向对象的c语言,简称obj-c或者OC OC和C的区别 1.OC是C语言的超集,OC是在C语言的基础上结合smalltalk的优点,开发出来的语言.oc兼容所有 ...
- 分类算法简介 分类: B10_计算机基础 2015-03-09 11:08 257人阅读 评论(0) 收藏
一.决策树 决策树是用于分类和预测的主要技术之一,决策树学习是以实例为基础的归纳学习算法,它着眼于从一组无次序.无规则的实例中 推理出以决策树表示的分类规则.构造决策树的目的是找出属性和类别间的关系, ...
随机推荐
- frame、bounds表示大小和位置的属性以及center、position、anchorPosition
在iOS开发开发过程中经常会用到界面元素的frame.bounds表示大小和位置的属性以及center.position.anchorPosition等单纯表示位置的属性.这些属性究竟什么含义?彼此间 ...
- postgresql 在linux上的源码安装
http://my.oschina.net/hippora/blog/375292 下载源码并解压 [root@fnddb ~]# wget https://ftp.postgresql.org/pu ...
- (转)Unity3D移动平台动态读取外部文件全解析
Unity3D移动平台动态读取外部文件全解析 c#语言规范 阅读目录 前言: 假如我想在editor里动态读取文件 移动平台的资源路径问题 移动平台读取外部文件的方法 补充: 回到目录 前言: 一直有 ...
- 学习笔记——装饰器模式Decorator
装饰器模式,最典型的例子. 工厂新开了流水线,生产了手机外壳,蓝天白云花色.刚准备出厂,客户说还要印奶牛在上面,WTF…… 时间上来不及,成本也不允许销毁了重来,怎么办?弄来一机器A,专门在蓝天白云的 ...
- 最小生成树Prim
首先解释什么是最小生成树,最小生成树是指在一张图中找出一棵树,任意两点的距离已经是最短的了. 算法要点: 1.用book数组存放访问过的节点. 2.用dis数组保存对应下标的点到树的最近距离,这里要注 ...
- MyEclipse8.5安装findbugs方法
step 1:首先从官网下载findbugs插件: edu.umd.cs.findbugs.plugin.eclipse_1.3.9.20090821.zipstep 2:将解压之后的edu.umd. ...
- 如何获取url访问历史记录
在院里的群里,有人问了这么一个问题: A页面提交表单到B页面,然后在B页面点了后退,如果在A页面上判断是直接访问的还是后退进去的呢?我不想改B页面. 于是乎本着热心人的想法,我就帮他搞了搞,首先我想到 ...
- dom4j解析xml实例
dom4j是一个java的XML API,类似jdom,用来读写XML文件,它性能优异.功能强大和极易使用等特点 所用jar包:dom4j-1.6.1.jar 需要解析的xml文件:people.xm ...
- Android--->activity界面跳转,以及查看生命周期过程
main.xml界面布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns ...
- 转:web_submit_data和web_submit_form的差别
在LoadRunner中有两个常用函数:Web_submit_form和Web_submit_data,在群里有人问这两个函数有什么区别.为什么会有两个不同却功能相似的函数.区别在哪里. 首先,从工具 ...