iOS动画三板斧(三)--UIDynamic动画介绍实战

终于到了动画三板斧第三篇了,这里用UIDynamic来实现动画。 UIDynamic是iOS 7之后新添加的一些物理仿真动画库,包含在UIKit框架中。

介绍

使用UIDynamic,需要理解几个概念:1、UIDynamicAnimator,2、UIDynamicBehavior,3、UIDynamicItem。

  • UIDynamicAnimator 相当于动画引擎。它初始化时,需要一个ReferenceView,用它的坐标系统作为参考坐标系。
  • UIDynamicBehavior 相当于仿真动画体。创建时,需要附带动画将要作用的视图(即UIDynamicItem),可以传一个包含多个视图的数组。
  • UIDynamicItem 就是仿真动画将要作用的视图。

常用的UIDynamicBehavior有:

  • UIGravityBehavior 重力行为
  • UICollisionBehavior 碰撞行为
  • UIAttachmentBehavior 附着行为
  • UIPushBehavior 推动行为
  • UIDynamicItemBehavior 动力行为
  • UISnapBehavior 捕获行为

以上每种行为都可以单独使用,也可以组合使用来实现复杂的动画效果。

实战

创建动画引擎

_animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];

给视图添加仿真行为

1.UIGravityBehavior (重力行为)
- (void)animateTest
{
    UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[_someView]];
    gravityBehavior.gravityDirection = CGVectorMake(0, 1);
    gravityBehavior.magnitude = 2.5;
    [_animator addBehavior:gravityBehavior];
}

gravityDirection是表示重力方向,这是二维坐标系中的方向,默认是(0.0,1.0),表示垂直向下,数值越大;数值可以为负,如(0.0,-1.0)就表示重力方向是垂直向上。也可以利用x和y来表示二维坐标系中的任意方向。例如(1.0,1.0)沿右下角45度方向,(1.0,100000)极度接近竖直向下方向。 magnitude表示力的系数,正数时,沿gravityDirection方向,数值越大,加速度越大;负数时,gravityDirection的反方向,数值越小,加速度越大。

2.UICollisionBehavior (碰撞行为)

在上述代码中,_someView视图会因为重力作用,直接掉出屏幕外。而添加碰撞行为,并设置好碰撞的边界时,_someView会在碰撞边界上回弹直至静止。

- (void)animateTest
{
    // 重力行为
    UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[_someView]];
    gravityBehavior.gravityDirection = CGVectorMake(0, 1);
    gravityBehavior.magnitude = 2.5;
    [_animator addBehavior:gravityBehavior];
    
    // 碰撞行为
    UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[_someView]];
    //设置碰撞边界有如下几张方式:
    //1.设置碰撞边界为referenceView的边界。
//    collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
    // 2.设置碰撞边界以referenceView作为参考,设置insets作为边界。
    [collisionBehavior setTranslatesReferenceBoundsIntoBoundaryWithInsets:UIEdgeInsetsMake(0, 0, 20, 0)];
    // 3.用两个点的连线作为碰撞边界
//    [collisionBehavior addBoundaryWithIdentifier:@"pointBoundary" fromPoint:CGPointMake(0, 300) toPoint:CGPointMake(320, 600)];
    // 4.以某个贝塞尔曲线作为碰撞边界
//    [collisionBehavior addBoundaryWithIdentifier:@"pathBoundary" forPath:_bezierPath];
    [_animator addBehavior:collisionBehavior];
}

添加碰撞行为后.gif

3.UIAttachmentBehavior (附着行为)

附着行为一般都是添加手势,让视图跟着手势移动,因为一般都是与手势搭配使用。

- (void)panAction:(UIPanGestureRecognizer *)panGesture
{
    CGPoint location = [panGesture locationInView:self.view];
    if (panGesture.state == UIGestureRecognizerStateBegan) {
        _attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:_someView attachedToAnchor:location];
        [_animator addBehavior:_attachmentBehavior];
    } else if (panGesture.state == UIGestureRecognizerStateChanged) {
        _attachmentBehavior.anchorPoint = location;
    } else if (panGesture.state == UIGestureRecognizerStateEnded) {
        [_animator removeBehavior:_attachmentBehavior];
    }
}

附着行为.gif

4.UIPushBehavior(推动行为)

推动行为的mode有连个值,一个是持续的推力,一个是初始推力。 pushDirection与重力的参数类似,表示二维坐标系中推力的方向。 magnitude系数,影响加速度。 下面的动画,是给视图一个向上的推力,然后在重力的作用下运动到最高点后下落,最后在设置好的碰撞边界处慢慢趋于静止。

- (void)animateTest
{
    // 推动行为
    UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[_someView] mode:UIPushBehaviorModeInstantaneous];
    pushBehavior.pushDirection = CGVectorMake(0, - 80.0);
    pushBehavior.magnitude = 2.0;
    [_animator addBehavior:pushBehavior];
    
    // 重力行为
    UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[_someView]];
    gravityBehavior.gravityDirection = CGVectorMake(0, 1);
    gravityBehavior.magnitude = 2.5;
    [_animator addBehavior:gravityBehavior];

    // 碰撞行为
    UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[_someView]];
    //设置碰撞边界为referenceView的边界。
    collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
    [_animator addBehavior:collisionBehavior];
}

推动行为.gif

5.UIDynamicItemBehavior (动力行为)

因为可以设置摩擦力、弹力、密度、阻力等参数,在模拟视图运动的能量损失。

- (void)animateTest
{
    //动力行为
    UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[_someView]];
    itemBehavior.elasticity = 0.6; //弹力
    itemBehavior.friction = 1;     //摩擦力
    itemBehavior.density = 10;    //密度
    itemBehavior.resistance = 10; // 阻力
    itemBehavior.allowsRotation = YES; //允许旋转
    [_animator addBehavior:itemBehavior];
    
    // 推动行为
    UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[_someView] mode:UIPushBehaviorModeInstantaneous];
    pushBehavior.pushDirection = CGVectorMake(0, - 80.0);
    pushBehavior.magnitude = 2.0;
    [_animator addBehavior:pushBehavior];

    // 碰撞行为
    UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[_someView]];
    //设置碰撞边界为referenceView的边界。
    collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
    [_animator addBehavior:collisionBehavior];
}

给视图一个初始向上的推力,然后在摩擦力,阻力等参数下慢慢减速至静止。遇到边界碰撞时会有能量损失。效果图如下:

动力行为.gif

6.UISnapBehavior (捕获行为)

捕获行为,是移动视图到某个位置,然后到达后,有一个摆动效果。

- (void)animateTest
{
    // 捕获行为
    UISnapBehavior *snapBehavior = [[UISnapBehavior alloc] initWithItem:_someView snapToPoint:self.view.center];
    snapBehavior.damping = 0.1; // 0.0~~1.0,阻尼系数,影响能量损失。
    [_animator addBehavior:snapBehavior];
}

捕获行为.gif

动画的触发,我这里是给self.view添加了一个点击手势和pan手势。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(animateTest)];
    [self.view addGestureRecognizer:gesture];
    
    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
    [self.view addGestureRecognizer:panGesture];
    
    _someView = [[UIView alloc] initWithFrame:CGRectMake(100, 200, 50, 50)];
    _someView.backgroundColor = [UIColor redColor];
    [self.view addSubview:_someView];

    _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
}

看一个斯坦福公开课中,显示的动画,也是用动态仿真动画实现的。

示例动画.gif

多种仿真效果组合,可以组合出酷炫的动画效果。大家可以多尝试组合以及参数变化来做酷炫的动画,Have fun!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ThoughtWorks

前端不止:Retina屏幕下两倍图

所见不一定即所得 眼睛是心灵的窗户,也是蒙蔽你的一种途径。 假设,我给你一张图片,你觉得肉眼可以观察到全部的细节吗? ? ---- 屏幕上一张清晰的图片 肉眼...

44750
来自专栏Material Design组件

Human Interface Guidelines — Sliders

10020
来自专栏十月梦想

移动端开发初识

对于pc端的前端开发以及html5和css3学习过后对页面布局更加熟练了,对于现在开发更多倾向于移动端开发,对于移动端开发和传统PC开发又有所不同,下面简单认识...

9240
来自专栏我和未来有约会

Silverlight 4 中摄像头的运用—part1

入的视频 摄像头经过一个Video对象就能让你看到视频,而这个对象是一个显示对象,所以显示对象能做得事情,它都能做,比如滤镜,变形,混合模式等等。当然最强大的还...

215100
来自专栏糊一笑

那些年下过的大雨

想了解一下用纯CSS和JS怎么实现一段下雨的动画,于是去CodePen上面搜了一下,发现了很多很有意思的东西。有空可以常去上面逛逛,在对技术产生敬畏的同时也能学...

35250
来自专栏Android机动车

开发中的动效设计与实现 —— 贝塞尔曲线动画的插值法

一个动画一般有这些参数 —— 动画时间、属性变化量、以及贝塞尔插值曲线。在动效标注的时候,也只需要标注这些参数就可以完整的给UI研发写动效了。一个动效所涉及的元...

21020
来自专栏数据小魔方

think-cell char 4——瀑布图案例应用

今天要分享的是瀑布图的两个案例应用。 因为瀑布图的用法比较特殊,在数据组织方面需要很强的技巧,所以这里再用两个案例来讲解瀑布图的用法。 ? ? 首先来看第一个案...

73370
来自专栏IT派

教你用CSS做一个社会人

小猪佩奇的火,其实一开始我是不屑的。纵观小朋友的历届动画,无论喜洋洋、熊出没还是小兔兵兵、小熊维尼,火过一阵便迅速陨落,回想起来也没多少沉淀的东西。所以一开始让...

11620
来自专栏数据小魔方

sparklines迷你图系列12——Composition(Pie)

今天分享sparklines迷你图系列13——Composition(Pie)。 大家看到名字就肯定知道是饼图了。借助sparklines迷你图工具,我们可以通...

27970
来自专栏量子位

谷歌发明图片批量去水印新算法,呼吁素材网站将水印随机化

安妮 编译整理 量子位 出品 | 公众号 QbitAI 图片素材网站为了保护版权,通常要将图片打个水印。 但最近,谷歌的研究人员发现了一种新算法,可以轻松批量将...

45850

扫码关注云+社区

领取腾讯云代金券