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) 收藏的更多相关文章

  1. 利用OpenMP实现埃拉托斯特尼(Eratosthenes)素数筛法并行化 分类: 算法与数据结构 2015-05-09 12:24 157人阅读 评论(0) 收藏

    1.算法简介 1.1筛法起源 筛法是一种简单检定素数的算法.据说是古希腊的埃拉托斯特尼(Eratosthenes,约公元前274-194年)发明的,又称埃拉托斯特尼筛法(sieve of Eratos ...

  2. 将HTML格式的String转化为HTMLElement 分类: C1_HTML/JS/JQUERY 2014-08-05 12:01 1217人阅读 评论(0) 收藏

    代码如下: <meta charset="UTF-8"> <title>Insert title here</title> </head& ...

  3. Mahout快速入门教程 分类: B10_计算机基础 2015-03-07 16:20 508人阅读 评论(0) 收藏

    Mahout 是一个很强大的数据挖掘工具,是一个分布式机器学习算法的集合,包括:被称为Taste的分布式协同过滤的实现.分类.聚类等.Mahout最大的优点就是基于hadoop实现,把很多以前运行于单 ...

  4. iOS开发之监听键盘高度的变化 分类: ios技术 2015-04-21 12:04 233人阅读 评论(0) 收藏

    最近做的项目中,有一个类似微博中的评论转发功能,屏幕底端有一个输入框用textView来做,当textView成为第一响应者的时候它的Y值随着键盘高度的改变而改变,保证textView紧贴着键盘,但又 ...

  5. iOS搜索框UISearchBar 分类: ios技术 2015-04-03 08:55 82人阅读 评论(0) 收藏

    当你在seachBar中输入字母之前的时候,只是用鼠标选中searchBar的时候,如图 终端输出截图如下:(这个时候调用先shouldBeginEditing,之后调用didBeginEditing ...

  6. C语言基础:函数指针 分类: iOS学习 c语言基础 2015-06-10 21:55 15人阅读 评论(0) 收藏

    函数指针:指向函数的指针变量. 函数名相当于首地址. 函数指针定义:返回值类型  (*函数指针变量名)(参数类型1,参数类型2,....)=初始值 函数指针类型:返回值类型  (*)(参数类型1,参数 ...

  7. OC基础:NSString NSNumber 分类: ios学习 OC 2015-06-17 17:55 77人阅读 评论(0) 收藏

    OC中的基本数据类型 NSString  在64位系统下,相当于long,在非64位系统下,想当于int. CGFloat   在64位系统下,相当于double,在非64位系统之下,想当与float ...

  8. 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兼容所有 ...

  9. 分类算法简介 分类: B10_计算机基础 2015-03-09 11:08 257人阅读 评论(0) 收藏

    一.决策树 决策树是用于分类和预测的主要技术之一,决策树学习是以实例为基础的归纳学习算法,它着眼于从一组无次序.无规则的实例中 推理出以决策树表示的分类规则.构造决策树的目的是找出属性和类别间的关系, ...

随机推荐

  1. js表单提交,判断文本框,用户名密码是否为空,JS表单检测!

    当表单提交时先触发验证的js代码,当验证表单的方法返回true时才会提交表单返回false则不提交数据<script type="text/javascript">fu ...

  2. Issue 5158: Modal dialog present (UnexpectedAlertOpen) issue in IE (Similar issue like 3360)

    https://code.google.com/p/selenium/issues/detail?id=5158   Reported by mailtopa...@gmail.com, Feb 13 ...

  3. HDU 5741 Helter Skelter

    离线处理+扫描线.题意很容易转化:若干个矩形形成并集,询问一些点是否在并集中? 官方题解不是这样做的....那种做法效率更高,暂时还不会.我这样是4500ms G++过的,C++TLE...... 区 ...

  4. Android Studio开发环境的配置

    为了使开发人员与时俱进, 在这里给大家讲解一下Android Studio的安装步骤及设置. 使用的是Android的最新版本,0.4.2版本,Android Studio可以脱离Eclipse单独运 ...

  5. 深入理解React、Redux

    深入理解React.ReduReact+Redux非常精炼,良好运用将发挥出极强劲的生产力.但最大的挑战来自于函数式编程(FP)范式.在工程化过程中,架构(顶层)设计将是一个巨大的挑战.要不然做出来的 ...

  6. JSP文件上传--Smartupload组件

    把smartupload.jar copy到D:\apache-tomcat-7.0.57\lib下. 创建htm上传文件:smartupload_demo01.htm 由于是上传文件,需要对表单进行 ...

  7. stock 财务 指标

    净资产收益率:"不能比利率低"每股收益是烟幕弹 有一点需要提请大家注意,观察净资产收益率至少要看过去三年的指标,如果公司没有经过大的资产重组,最好看看自其上市以来每一年的净资产收益 ...

  8. ext3文件系统目录限制问题

    昨晚排查了在KVM的build系统中的一个问题,跟踪到后面发现在一个目录下mkdir创建目录失败.我手动试了一下,提示如下:cannot create directory `/home/master/ ...

  9. A Game

    A Game 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Little Hi and Little Ho are playing a game. There is a ...

  10. 删除DriverStore\FileRepository文件夹后,设备驱动无法安装,提示“没有为设备信息集或元素选择驱动程序(代码 28)”的解决办法

    前言: 我前几天手贱,整个FileRepository删除掉了,之后重启就出现了让人蛋疼的这个问题,因为出于各种原因不想重装系统,百度轮番换搜索词无果,虽然驱动装上了但新设备依然无法自动安装驱动等“一 ...