博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android属性动画全解析
阅读量:6069 次
发布时间:2019-06-20

本文共 8367 字,大约阅读时间需要 27 分钟。

属性动画之ViewPropertyAnimator

这是属性动画最简单的一种

代码也最简单

iv.animate().translationY(500);复制代码

通常一些简单的android 原生的view动画 我们都优先考虑这种方法,因为真的很方便啊。

/**     * 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;    }复制代码

看下这个函数返回就知道了。

有很多方法可以供我们选择,具体各位自查。

总体来说ViewPropertyAnimator 使用简单也比较好理解,也支持链式调用。不再多说

ObjectAnimator

ViewPropertyAnimator虽然好用,但是自定义view很难使用这个,且支持的属性有限。很多情况我们要自己支持一些属性

就得用到ObjectAnimator

总体来说 分几步:

  1. 动画执行过程中要改变的属性 必须有gettter和setter方法
  2. ObjectAnimator.ofXXX() 创建 ObjectAnimator 对象
  3. 最后start执行动画即可

看下代码:

public class LoadingView extends View {    Paint mPaint = new Paint();    public float getProgress() {        return progress;    }    public void setProgress(float progress) {        this.progress = progress;        //setter方法是肯定会被ObjectAnimator调用的,调用完以后 我们要主动invalidate方法        //onDraw方法才会主动执行,否则,只改变一个属性的值而不重绘 肯定是没效果的。        //这也就是为什么属性动画 不是直接更改属性的值,而要调用属性的setter方法,因为直接        //更改属性的值 invalidate没地方调用了,动画自然没效果了。        invalidate();    }    /**     * 进度条     */    float progress = 0;    public LoadingView(Context context) {        super(context);    }    public LoadingView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //这里没有用0,0  width,hegiht 这2个点来定位这个矩形 是因为我们的圆形边有宽度,所以要        //稍微窄一点 不然的话 边界处会有丢失的部分 很难看        RectF oval = new RectF(10, 10,                getWidth()-10, getHeight()-10);        //先画圆弧        mPaint.setColor(Color.RED);        mPaint.setStyle(Paint.Style.STROKE);        mPaint.setStrokeWidth(20);        canvas.drawArc(oval, -90, 360 * progress/100, false, mPaint);        //再画文字        mPaint.reset();        mPaint.setColor(Color.BLUE);        mPaint.setTextSize(80);        mPaint.setTextAlign(Paint.Align.CENTER);        canvas.drawText((int)progress + "%", oval.centerX(), oval.centerY(), mPaint);    }}复制代码
// 创建 ObjectAnimator 对象                ObjectAnimator animator = ObjectAnimator.ofFloat(loadingView, "progress", 0, 85);                animator.setDuration(3000);                animator.start();复制代码

ofXXX有很多方法,可以满足我们任何自定义view属性的要求。

Interpolator 插值器

这个其实挺好理解的,打个比方 一个人从起跑点0m处跑到终点100m处。可以有很多种跑法

  1. 一直加速跑 跑到终点
  2. 跑到一半减速再加速到终点
  3. 跑到一半停下来休息一下 再跑到终点
  4. .....等等 有无限种跑法 ,全看你自己想怎么跑。甚至都可以跑过终点跑到150m处再跑回去

Interpolator 也是这样,Interpolator 就是设置你动画执行过程的,以不同的速度模型来将你的动画执行完毕

系统自带的Interpolator已经足够多,我不准备一一介绍了,网上太多资料了,自己跑跑看就可以了。

PathInterpolator这个较为特殊,尤其是配合 贝塞尔曲线使用的时候 会有很多酷炫的特效,我写个简单的 demo 大家体会一下这其中的奥妙即可。 讲白了还是那个跑步的跑法 可以由我们自己设定

Path interpolatorPath = new Path();                // 先以「动画完成度 : 时间完成度 = 1 : 1」的速度匀速运行 25% 50的百分之25 就是12.5                interpolatorPath.lineTo(0.25f, 0.25f);                // 然后瞬间跳跃到 100% 的动画完成度  在这里其实也就是从50 直接跳跃到100 也就是圆形直接画满                interpolatorPath.moveTo(0.25f, 2.0f);                // 再匀速倒车,返回到目标点     画满以后 再回到 目标值                interpolatorPath.lineTo(1, 1);                // 创建 ObjectAnimator 对象                ObjectAnimator animator = ObjectAnimator.ofFloat(loadingView, "progress", 0, 50);                animator.setDuration(3000);                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {                    PathInterpolator pathInterpolator=new PathInterpolator(interpolatorPath);                    animator.setInterpolator(pathInterpolator);                }                animator.start();复制代码

ofXXX方法无法满足我咋办?Evaluator来帮你

比如说我自定义了某个view,这个view要完成我想要的动画需要改变的属性是一个自定义对象那咋办呢?自定义Evaluator呗

稍微改变下我们的代码:

public class LoadingView extends View {    Paint mPaint = new Paint();    public CustomProperty getCustomProperty() {        return customProperty;    }    public void setCustomProperty(CustomProperty customProperty) {        this.customProperty = customProperty;        invalidate();    }    /**     * 进度条     */    CustomProperty customProperty = new CustomProperty(0,0);    public LoadingView(Context context) {        super(context);    }    public LoadingView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        RectF oval = new RectF(30, 30,                getWidth()-30, getHeight()-30);        //先画圆弧        mPaint.setColor(Color.RED);        mPaint.setStyle(Paint.Style.STROKE);        mPaint.setStrokeWidth(customProperty.getStrokeWidth());        canvas.drawArc(oval, -90, 360 * customProperty.getProgress()/100, false, mPaint);    }}复制代码

自定义属性

public class CustomProperty {    float progress;    public CustomProperty(float progress, int strokeWidth) {        this.progress = progress;        this.strokeWidth = strokeWidth;    }    public float getProgress() {        return progress;    }    public void setProgress(float progress) {        this.progress = progress;    }    public int getStrokeWidth() {        return strokeWidth;    }    public void setStrokeWidth(int strokeWidth) {        this.strokeWidth = strokeWidth;    }    @Override    public String toString() {        return "CustomProperty{" +                "progress=" + progress +                ", strokeWidth=" + strokeWidth +                '}';    }    int strokeWidth;}复制代码

最重要的自定义Evaluator

class CustomPropertyEvaluator implements TypeEvaluator
{ CustomProperty customProperty=new CustomProperty(0,0); @Override public CustomProperty evaluate(float fraction, CustomProperty startValue, CustomProperty endValue) { float progress=startValue.progress+ fraction*endValue.getProgress(); int strokeWidth=(int)(startValue.strokeWidth+fraction*endValue.getStrokeWidth()); customProperty.setProgress(progress); customProperty.setStrokeWidth(strokeWidth); return customProperty; } }复制代码

最后调用动画

// 创建 ObjectAnimator 对象                ObjectAnimator animator = ObjectAnimator.ofObject(loadingView, "customProperty", new CustomPropertyEvaluator(),new CustomProperty(0,0), new CustomProperty(75,30));                animator.setDuration(3000);                animator.start();复制代码

然后看下我们的效果:

PropertyValuesHolder 组合动画

组合动画无非就是动画执行的顺序集合,大概也就是分三种,先说前两种

一起执行和顺序执行

//ofPropertyValuesHolder 代表一起执行动画的集合,holder1 holder2 holder3 可以一起执行 共享一个插值器 interpolator                PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1);                PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1);                PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1);                ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(loadingView, holder1, holder2, holder3);                animator.start();                AnimatorSet animatorSet=new AnimatorSet();                ObjectAnimator animator1 = ObjectAnimator.ofPropertyValuesHolder(loadingView, holder1, holder2, holder3);                ObjectAnimator animator2 = ObjectAnimator.ofPropertyValuesHolder(loadingView, holder1, holder2);                //如果需要动画依次播放:                animatorSet.playSequentially(animator1,animator2);                //也可以指定顺序                animatorSet.play(animator1).before(animator2);                animatorSet.start();复制代码

比较好理解是吧。这里就不上效果图了,自己试试就知道。

最后一种关键帧动画着重说一下,还记得前面插值器的介绍吗?有一个path插值器的,我们写了个demo带有回弹效果的, 利用关键帧动画的写法 可以不用那么复杂的插值器即可完成

//从0开始                Keyframe keyframe1 = Keyframe.ofFloat(0, 0);                //时间走到一半 我们应该圆圈画完                Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);                //时间走完的时候 我们的圆圈应该回到一半的位置                Keyframe keyframe3 = Keyframe.ofFloat(1, 50);                PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3);                ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(loadingView, holder);                animator.setDuration(3000);                animator.start();复制代码

转载地址:http://fifgx.baihongyu.com/

你可能感兴趣的文章
linux系列博文---->深入理解linux启动运行原理(一)
查看>>
Android反编译(一) 之反编译JAVA源码
查看>>
结合当前公司发展情况,技术团队情况,设计一个适合的技术团队绩效考核机制...
查看>>
python-45: opener 的使用
查看>>
cad图纸转换完成的pdf格式模糊应该如何操作?
查看>>
Struts2与Struts1区别
查看>>
网站内容禁止复制解决办法
查看>>
Qt多线程
查看>>
我的友情链接
查看>>
Ubuntu12.04 编译android源代码及生成模拟器经历分享
查看>>
KVM网络桥接设置方法
查看>>
Puppet学习手册:Puppet Yum安装
查看>>
我的友情链接
查看>>
ansible学习记录
查看>>
网思科技校园网计费解决方案
查看>>
我的友情链接
查看>>
携程 Apollo分布式部署
查看>>
2017 Hackatari Codeathon B. 2Trees(深搜)(想法)
查看>>
单词统计
查看>>
输入一个数字计算圆的面积
查看>>