Android 中基于物理特性的动画简介
sfco7351
7年前
<p><img src="https://simg.open-open.com/show/893895d5eda3dafbea9030706bb9fcd9.png"></p> <p><strong>简评:</strong> 基于物理特性的动画依赖于物理学定律,这能在动画中表现出高度的现实感。</p> <h2><strong>什么是基于物理的动画?</strong></h2> <ul> <li>这是一种遵循物理学定律的动画形式</li> <li>能够依据加速度和速度去计算和更新每一帧的动画数值</li> <li>当受力平衡时,动画为处于恒定运动或静止状态</li> </ul> <h2><strong>和普通动画有什么不一样?</strong></h2> <ul> <li>自然:动画模仿实时的动作,看起来更自然</li> <li>反应:当目标值发生变化时,动画保持动量(速度)并以更平滑的运动结束</li> <li>较少的视觉干扰:动画看起来更流畅,反应灵敏度也更高</li> </ul> <p>考虑在动画期间目标值需要改变的情况。</p> <p><img src="https://simg.open-open.com/show/f5ce0df39a920ce8fd2eea66c2daf898.gif"></p> <pre> <code class="language-java">左侧使用 ObjectAnimator 构建的动画以及右侧基于物理 API 的动画差异</code></pre> <p>使用 <strong>Animator</strong> 构建的动画是一种恒定速率的形式,并且具有固定的持续时间。为了适应目标值的变化,您需要在目标值更改时取消动画,将当前值的动画重新配置为新的起始值,并添加新的目标值。</p> <p>在视觉上,这个过程中在动画里创建了一个突然停止,并且之后又突然运动的一个不连贯的动作。</p> <p>而使用 <strong>基于物理的动画 API</strong> 构建的动画则自然得多。目标值的变化导致力的变化,新的运动适用于现有的速度,而且是连续过渡到新的目标,这样的过程显示的动画效果更符合人们的日常认知。</p> <h2><strong>添加基于物理的动画支持库</strong></h2> <p>为了开始使用基于物理的动画,将这个库添加到 build.gradle 文件中:</p> <pre> <code class="language-java">compile "com.android.support:support-dynamic-animation:25.4.0"</code></pre> <p>该库提供了两个 Animation 类:SpringAnimation 和 FlingAnimation</p> <h2><strong>弹簧动画(Spring Animation)</strong></h2> <p>弹簧大家都知道,拉伸时会缩回去,压缩时又会弹回来。</p> <p>应用到 App 中就是这样一个效果:</p> <p><img src="https://simg.open-open.com/show/b09e1b55b7f7920e512a00cb63a2d97d.gif"></p> <pre> <code class="language-java">Spring translate animation applied on an ImageView</code></pre> <p>现在,让我们先了解一下 Spring 的属性,然后再看看如何实现:</p> <h2><strong>弹力(Spring Force)</strong></h2> <p>SpringForce 类允许开发者通过改变弹簧的阻尼比,刚度和静止位置来控制弹簧的性能。一旦动画开始,弹簧力就会更新动画值和每帧的速度。动画继续,直到控件受力平衡。</p> <p><strong>阻尼比(Damping ratio):</strong> 受力平衡前的振荡次数。您可以通过它来改变弹簧的弹性,阻尼比为零将无限振荡,高阻尼比将很快停止动画。</p> <p>阻尼比可以从高弹性到无弹性常数。</p> <pre> <code class="language-java">DAMPING_RATIO_HIGH_BOUNCY = 0.2f; // more oscillations DAMPING_RATIO_NO_BOUNCY = 1f; // very few oscillations</code></pre> <p><strong>刚度(Stiffness):</strong> 振荡速度。这将控制物体快速恢复到其静止位置。</p> <pre> <code class="language-java">STIFFNESS_HIGH = 10_000f; // would quickly come back to its resting position STIFFNESS_VERY_LOW = 50f; // would slowly come back, like a loose suspension</code></pre> <p><strong>平衡位置(Resting position):</strong> 弹力达到平衡的位置。</p> <p>为了实现上面所示的动画,我们创建一个 SpringAnimation 类的实例:</p> <pre> <code class="language-java">SpringAnimation springX = new SpringAnimation(mViewToBeAnimated, new FloatPropertyCompat<View>("translationX") { @Override public float getValue(View view) { return view.getTranslationX(); } @Override public void setValue(View view, float value) { view.setTranslationX(value); } }); SpringForce springForceX = new SpringForce(0f); springForceX.setStiffness(SpringForce.STIFFNESS_MEDIUM); springForceX.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY); springX.setSpring(springForceX); springX.start();</code></pre> <p>对于构造函数 SpringAnimation,我们提供我们想要动画化的视图,以及我们想要动画化的属性。在这种情况下 imageView,我们想要动画的对象是 TRANSLATION_X,我们想要动画的属性是左右颠倒视图。</p> <p>我们创建一个 springForce 实例,并将弹簧的最终静止位置的值设置为零,以便视图能回到起始点。</p> <p>最后弹簧动画效果就大功告成了!开不开心!</p> <h2><strong>抛掷动画(Fling Animation)</strong></h2> <p>现在弹出一个控件之后,让我们看看如何做出像现实中物体上抛的效果。</p> <p>上抛运动大家也都很熟悉,在现实世界中向上扔一个物体,它会有一个初速度,然后它在这个速度的惯性下继续运动,直到引力的作用下逐渐停止。</p> <p>为了模拟上抛运动向上阶段的过程,我们将使用 FlingAnimation 库中可用的类。</p> <p>先看个例子,在横轴和纵轴上移动一个物体,它的效果:</p> <p><img src="https://simg.open-open.com/show/09de54af22c1c55ae500d9b68e12227d.gif"></p> <pre> <code class="language-java">Fling translate animation applied on an ImageView</code></pre> <p>为了接收 callbacks,当动作开始时,我们需要设置一个姿势监听器。一旦检测到这个回来的姿势,我们会收到 onFling 回调,同时在坐标轴上有一个 downEvent,一个 upEvent 和一个速度(以每秒移动的单位像素为单位)。</p> <h2><strong>设置 StartVelocity</strong></h2> <p>默认情况下,起始速度设置为零像素 / 秒。在这种情况下,它会在下一帧中停止动画。因此,您必须定义起始速度,以确保动画不会马上结束。</p> <h2><strong>设置最小值和最大值</strong></h2> <p>要在特定范围内为属性值设置动画时,请设置最小和最大动画值。一旦 Fling 动画达到其最小 动画值或最大动画值,它将立即结束。</p> <h2><strong>设置反作用力</strong></h2> <p>需要设置反作用力来控制动画变慢时的速度 <strong>,</strong> 现在我们准备创建一个 Fling 动画:</p> <pre> <code class="language-java">private GestureDetector.OnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() { ... @Override public boolean onFling(MotionEvent downEvent, MotionEvent moveEvent, float velocityX, float velocityY) { //Fling Right/Left FlingAnimation flingX = new FlingAnimation(mViewTobeFlung, DynamicAnimation.TRANSLATION_X); flingX.setStartVelocity(velocityX) .setMinValue(MIN_TRANSLATION) // minimum translationX property .setMaxValue(maxTranslationX) // maximum translationX property .setFriction(FRICTION) .start(); return true; } }</code></pre> <p>对于 FlingAnimation 构造函数,我们提供我们想要的动画对象和要动画化的属性。在这种情况下 imageView,我们想要动画的对象是 TRANSLATION_X,最后,在 onFling() 方法中启动 fling 动画。</p> <h2><strong>结论</strong></h2> <p>使用新的基于物理的动画系统,我们不需要为创建基于物理的动画提供持续时间或开始和结束值。Google 已经开放接口让开发人员能轻松创建酷炫动画,只需几行代码即可模拟物理定律。</p> <p>来自:https://zhuanlan.zhihu.com/p/28239508</p> <p> </p>