摘要:上期文章镇楼这可能是第二好的自定义教程之绘制凯哥的文章确实写的细而好呀,这不,活生生把面试系列先放一放,继续讲解我们的动画。这一块比较简单,我们可以直接引用凯哥这里的总结图。哦,还有一个最重要的原则就是,盯紧扔物线凯哥,加入我们的大军吧。
上期文章镇楼:
这可能是第二好的自定义 View 教程之绘制
凯哥的文章确实写的细而好呀,这不,活生生把 面试系列 先放一放,继续讲解我们的动画。
不是讲所有动画Android 里面对动画可以进行一些分类,主要分为两类:
Animation
Transition
由于 「Transtion」 重点在于切换而不是动画,所以我们今天直接忽略。废话不用多说,那么我们就直接讲解属性动画「Property Animation」吧。
ViewPropertyAnimator现在的项目中的动画 99% 都是用的属性动画,所以我们不讲 View Animation。
这一块比较简单,我们可以直接引用凯哥这里的总结图。(凯哥文章,业界良心,真的很赞。)
从图中可以看到, View 的每个方法都对应了 ViewPropertyAnimator 的两个方法,其中一个是带有 -By 后缀的,例如,View.setTranslationX() 对应了 ViewPropertyAnimator.translationX() 和 ViewPropertyAnimator.translationXBy() 这两个方法。其中带有 -By() 后缀的是增量版本的方法,例如,translationX(100) 表示用动画把 View 的 translationX 值渐变为 100,而 translationXBy(100) 则表示用动画把 View 的 translationX 值 渐变地增加 100。
其中的 ViewPropertyAnimator 可以通过 View.animate() 得到。
/** * This method returns a ViewPropertyAnimator object, which can be used to animate * specific properties on this View. * * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. */ public ViewPropertyAnimator animate() { if (mAnimator == null) { mAnimator = new ViewPropertyAnimator(this); } return mAnimator; }ObjectAnimator
使用方式:
如果是自定义控件,需要添加 setter / getter 方法;
用 ObjectAnimator.ofXXX() 创建 ObjectAnimator 对象;
用 start() 方法执行动画。
其中特别需要注意的是:
setter() 方法需要调用 invalidate() 对 View 进行重绘。
**获取 ObjectAnimator 采用的是 ObjectAnimator.ofXXX() 方法。
至于是 「ofFloat」还是「ofInt」还是别的,这个完全视你的 View 参数而定,并且第二个参数用 setXXX 的「XXX」字符串。**
上面 ViewPropertyAnimator 方法基本都是通用的。
当然,当你看到 ObjectAnimator.ofObject() 方法的时候,你会心生疑惑,这其实就是为了对不限定类型的属性做动画。
例子也懒得写了,直接用凯哥的。
public class SportsView extends View { float progress = 0; ...... // 创建 getter 方法 public float getProgress() { return progress; } // 创建 setter 方法 public void setProgress(float progress) { this.progress = progress; invalidate(); } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); ...... canvas.drawArc(arcRectF, 135, progress * 2.7f, false, paint); ...... } } ...... // 创建 ObjectAnimator 对象 ObjectAnimator animator = ObjectAnimator.ofFloat(view, "progress", 0, 65); // 执行动画 animator.start();
当然,这些动画都是可以自由组合的,支持「链式调用」,因为它们返回的都是 ViewPropertyAnimator。
比如这样。
view.animate() .scaleX(1) .scaleY(1) .alpha(1);
而对于 ObjectAnimator,是不能这么用的。不过你可以使用 PropertyValuesHolder 来同时在一个动画中改变多个属性。
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1); PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1); PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1); ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3) animator.start();
从上面的 gif 图可以发现,动画是同步进行的,那要是我们希望依次执行怎么办?比如这样,先放大再平移。
万能的 Android 自然难不倒我们,这样就有了 AnimatorSet。
AnimatorSet 多个动画配合执行AnimatorSet.playSequentially(Animator... items) 完美地解决了我们上面的疑惑。
AnimatorSet animatorSet = new AnimatorSet(); // 两个动画依次执行 animatorSet.playSequentially(animator1, animator2); animatorSet.start();
其中 「animator1」和「animator2」分别是放大和平移的动画。
翻阅官方源码一看,其实不止 playSequentially() 一个方法,除了顺序执行,当然有其他方法,比如:
AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(animator1).before(animator2); // 先执行 1 再执行 2 animatorSet.playTogether(animator2, animator3); // 2 和 3 同时开始 animatorSet.start();
类似的处理方案,还很多很多方式,具体你可以查看官方源码。
仅靠这些方法做出来的动画效果说实话已经很炫了,不过我们总是不满足,比如我们设计师想这样怎么办?
图片中先是将进度填到了 100,再降回了实际的值。这利用上面所提到的知识,好像根本没法实现,这效果有意思,我们看看怎么实现。
PropertyValuesHolders.ofKeyframe() 把同一个属性拆分除了合并多个属性和调配多个动画,你还可以在 PropertyValuesHolder 的基础上更进一步,通过设置 Keyframe (关键帧),把同一个动画属性拆分成多个阶段。比如,要实现上面的效果,你只需:
// 在 0% 处开始 Keyframe keyframe1 = Keyframe.ofFloat(0, 0); // 时间经过 50% 的时候,动画完成度 100% Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100); // 时间见过 100% 的时候,动画完成度倒退到 80%,即反弹 20% Keyframe keyframe3 = Keyframe.ofFloat(1, 80); PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3); ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder); animator.start();
先小结一下,「关于复杂的属性关系来做动画」,就这么三种:
使用 PropertyValuesHolder 来对多个属性同时做动画;
使用 AnimatorSet 来同时管理调配多个动画;
PropertyValuesHolder 的进阶使用:使用 PropertyValuesHolder.ofKeyframe() 来把一个属性拆分成多段,执行更加精细的属性动画。
ValueAnimator实际上不太想说这个 ValueAnimator,因为它的使用场景确实不多。这里也不精挑细琢了,大概需要记得:
ViewPropertyAnimator 和 ObjectAnimator 的内部实现其实都是 ValueAnimator,ObjectAnimator 更是本来就是 ValueAnimator 的子类,它们三个的性能并没有差别。它们的差别只是使用的便捷性以及功能的灵活性。所以在实际使用时候的选择,只要遵循一个原则就行:尽量用简单的。能用 View.animate() 实现就不用 ObjectAnimator,能用 ObjectAnimator 就不用 ValueAnimator。
另外,它们还支持 setDuration(long duration) 设置动画持续时长以及 setInterpolator() 设置各种「速度设置器」。
速度设置器?「速度设置器」,简而言之就是动画的「速度模型」,这个方法可以让动画按照你想要的方式进行。一般情况我们都直接不设置个,所以下面的了解一下就好,甚至跳过也没事。
简单科普一下提供的「速度模型」,需要看效果的 点击这里。
AccelerateDecelerateInterpolator
先加速再减速。这是默认的「速度模型」,实际上就像开车一样,先加速启动,开一会再减速刹车停下。
LinearInterpolator
匀速模型,即动画是迅速进行的。
AnticipateOvershootInterpolator
带施法前摇和回弹的「速度模型」。
DecelerateInterpolator
持续减速到 0,动画开始的时候是最高速度,然后在动画过程中逐渐减速,直到动画结束的时候恰好减速到 0。
AccelerateInterpolator
持续加速。和上面那个刚刚相反。
AnticipateInterpolator
先回拉一下再进行正常动画轨迹。效果看起来有点像投掷物体或跳跃等动作前的蓄力。
OvershootInterpolator
动画会超过目标值一些,然后再弹回来。效果看起来有点像你一屁股坐在沙发上后又被弹起来一点的感觉。
AnticipateOvershootInterpolator
上面这两个的结合版:开始前回拉,最后超过一些然后回弹。
他娘的,太多啦,就不一一写完了,真没啥用处,用到再说嘛。
设置描述动画生命周期的监听器可以给动画设置监听器,分别有两种设置方式。
ViewPropertyAnimator.setListener(AnimatorListener listener)
ObjectAnimator.addListener(AnimatorListener listener)
可以看到,两种动画方式设置监听器有一点不同的是一个是 「set」,一个是「add」,但它们的参数都是一致的「AnimatorListener」。
AnimatorListener 有四个回调方法:
/** *Notifies the start of the animation.
* * @param animation The started animation. */ void onAnimationStart(Animator animation); /** *Notifies the end of the animation. This callback is not invoked * for animations with repeat count set to INFINITE.
* * @param animation The animation which reached its end. */ void onAnimationEnd(Animator animation); /** *Notifies the cancellation of the animation. This callback is not invoked * for animations with repeat count set to INFINITE.
* * @param animation The animation which was canceled. */ void onAnimationCancel(Animator animation); /** *Notifies the repetition of the animation.
* * @param animation The animation which was repeated. */ void onAnimationRepeat(Animator animation);
从代码中可以很清晰的看出:
在动画开始执行的时候,调用 onAnimationStart()
在动画结束后,将调用 onAnimationEnd()
在动画取消后,将调用 onAnimationCancel()
在动画重复执行的时候,将调用 onAnimationRepeat()
其中只需要注意两点:
动画被 cancel() 取消的时候,依然会调用 onAnimationEnd(),不过是在 onAnimationCancel() 之后。
**重复执行动画,通过 setRepeatMode() / setRepeatCount() 或者 repeat() 方法执行。
但但是!!!ViewProperAnimator 不支持重复。**
动画的属性更新监听器除了上面设置的动画生命周期监听器,我们还有其他的方法,比如 ViewPropertyAnimator.setUpdateListener() / ObjectAnimator.addUpdateListener()。
这两个方法虽然名称和可设置的监听器数量不一样,但本质其实都一样的,它们的参数都是 AnimatorUpdateListener。它只有一个回调方法:onAnimationUpdate(ValueAnimator animation)。
/** * Implementors of this interface can add themselves as update listeners * to anValueAnimator
instance to receive callbacks on every animation * frame, after the current frame"s values have been calculated for that *ValueAnimator
. */ public static interface AnimatorUpdateListener { /** *Notifies the occurrence of another frame of the animation.
* * @param animation The animation which was repeated. */ void onAnimationUpdate(ValueAnimator animation); }
当动画的属性更新时(不严谨的说,即每过 10 毫秒,动画的完成度更新时),这个方法被调用。
方法的参数是一个 ValueAnimator,ValueAnimator 是 ObjectAnimator 的父类,也是 ViewPropertyAnimator 的内部实现,所以这个参数其实就是 ViewPropertyAnimator 内部的那个 ValueAnimator,或者对于 ObjectAnimator 来说就是它自己本身。
小结还是做个小结,自定义 View 中我们使用属性动画主要分为三种方式:
ViewPropertyAnimator
ObjectAnimator
ValueAnimator
使用它们的任一个都不会有性能差异,只需记住一个原则,依次越来越难,能用简单的就用简单的。
哦,还有一个最重要的原则就是,盯紧「扔物线凯哥」,加入我们的「HenCoder」大军吧。
做不完的开源,写不完的矫情。欢迎扫描下方二维码或者公众号搜索「nanchen」关注我的微信公众号,目前多运营 Android ,尽自己所能为你提升。如果你喜欢,为我点赞分享吧~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/14019.html
摘要:而绘制的关键就是的使用的绘制类方法关键参数的辅助类方法范围裁切和几何变换。方法可能相对其它较难,但却是自定义实际应用中最多的。这里直接摘抄凯哥的自定义。 面试系列 不继续了吗? 知道我的人都知道,之前我写了这个 面试系列宣言,如今好像一直都没有连载,而是隔三差五地来一篇,其实也是因为笔者也能力有限,构思一篇文章需要足够的时间去印证其准确性,而之前的部分就因为印证不够造成了勘误。 值得...
摘要:自定义简单实现凹凸优惠券效果自定义属性的简单使用,继承重写方法使用来绘制,简单实现凹凸优惠券效果图文并茂自定义之切换标签自定义实现一个简单好用的切换标签自定义滑动确认控件自定义控件,用来进行滑动确认等操作。 Android 之自定义 View 的死亡三部曲之 Measure 我还不知道你的三围呢(你要占多少屏幕),我怎么能轻易让你出场呢? Android 自定义 View,ViewGr...
摘要:看到很多团队和开源项目都在用代码检查工具,自己一直没用过,最近加入了新团队有项目在用,就想着研究一下。代码校验工具能够让你在写代码时避免一些低级的错误。同时,也有友好的文档针对每一条规则。在上文提高的所有工具当中它对有着最好的支持。 看到很多团队和开源项目都在用代码检查工具,自己一直没用过,最近加入了新团队有项目在用,就想着研究一下。看到sitepoint上的一篇2015年的文章觉得不...
摘要:简明教程中文版上滚动动画使用,你可以快速实现垂直和水平滚动动画。下面的显示了一条微笑鱼的图像。不幸的是,浏览器不支持的,并且没有为此错误提供兼容性修补程序。这是为了防止用户在动画过程中重复按下按钮,这将构建动画队列。 Velocity.js简明教程(中文版上) 滚动动画 使用Velocity.js,你可以快速实现垂直和水平滚动动画。滚动可以与整个页面或元素相关。无论哪种方式,都要在即...
阅读 2600·2021-11-23 09:51
阅读 1902·2021-11-19 09:40
阅读 3392·2021-10-13 09:39
阅读 2234·2021-09-22 15:06
阅读 713·2019-08-30 15:55
阅读 3024·2019-08-30 15:44
阅读 1639·2019-08-30 14:05
阅读 3278·2019-08-29 15:24