PropertyValuesHolder的使用

本文深入讲解了Android属性动画的实现原理及使用技巧,包括PropertyValuesHolder、Keyframe的应用,以及如何通过不同方式组合动画实现复杂效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:
PropertyValuesHolder的使用

【HenCoder Android 开发进阶】自定义 View 1-7:属性动画(进阶篇)

《Animation动画详解》

Android 属性动画:这是一篇很详细的 属性动画 总结&攻略

属性动画需要了解的知识点:
ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback 
ObjectAnimator extends ValueAnimator
AnimatorSet extends Animator 
View的anim
public static Keyframe ofFloat(float fraction, float value)  

fraction:表示当前的显示进度,即从加速器中getInterpolation()函数的返回值;
value:表示当前应该在的位置 

第一步:生成Keyframe对象;
第二步:利用PropertyValuesHolder.ofKeyframe()生成PropertyValuesHolder对象
第三步:ObjectAnimator.ofPropertyValuesHolder()生成对应的Animator

同一个动画中改变多个属性:多个动画同时执行

方式一:ViewPropertyAnimator

view.animate()
        .scaleX(1)
        .scaleY(1)
        .alpha(1);

方式二: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();

方式三:AnimatorSet (可指定动画顺序)

ObjectAnimator animator1 = ObjectAnimator.ofFloat(...);
animator1.setInterpolator(new LinearInterpolator());
ObjectAnimator animator2 = ObjectAnimator.ofInt(...);
animator2.setInterpolator(new DecelerateInterpolator());

AnimatorSet animatorSet = new AnimatorSet();
// 两个动画依次执行
animatorSet.playSequentially(animator1, animator2);

// 两个动画同时执行
animatorSet.playTogether(animator1, animator2);

// 使用 AnimatorSet.play(animatorA).with/before/after(animatorB)
// 的方式来精确配置各个 Animator 之间的关系
animatorSet.play(animator1).with(animator2);
animatorSet.play(animator1).before(animator2);
animatorSet.play(animator1).after(animator2);

animatorSet.start();

PropertyValuesHolder的使用

通过设置 Keyframe (关键帧),把同一个动画属性拆分成多个阶段。

//1、设置关键帧
//参数:动画进度百分比,动画属性值
Keyframe.ofFloat(float fraction, float value)
Keyframe.ofInt(float fraction, int value)
Keyframe.ofObject(float fraction, Object value)

//2、将关键帧添加到PropertyValuesHolder
//参数:属性名(需要set/get方法),关键帧Keyframe
PropertyValuesHolder.ofKeyframe(String propertyName, Keyframe... values)
//参数:属性值、属性值
PropertyValuesHolder.ofFloat(String propertyName, float... values)
//参数:属性值、属性值
PropertyValuesHolder.ofInt(Property<?, Integer> property, int... values);
//参数:属性值、TypeEvaluator、属性值
PropertyValuesHolder.ofObject(String propertyName, TypeEvaluator evaluator, Object... values);

//3、添加到ObjectAnimator
//参数:执行动画的对象,属性值Holder
ObjectAnimator.ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)

PropertyValuesHolder使用示例:

KeyframeView

public class KeyframeView extends View {
    final float radius = dpToPixel(80);

    float progress = 0;
    RectF arcRectF = new RectF();

    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    public KeyframeView(Context context) {
        super(context);
    }

    public KeyframeView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public KeyframeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    {
        paint.setTextSize(dpToPixel(40));
        paint.setTextAlign(Paint.Align.CENTER);
    }

    public float getProgress() {
        return progress;
    }

    public void setProgress(float progress) {
        this.progress = progress;
        invalidate();
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        float centerX = getWidth() / 2;
        float centerY = getHeight() / 2;

        paint.setColor(Color.parseColor("#E91E63"));
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(dpToPixel(15));
        arcRectF.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
        canvas.drawArc(arcRectF, 135, progress * 2.7f, false, paint);

        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawText((int) progress + "%", centerX, centerY - (paint.ascent() + paint.descent()) / 2, paint);
    }
}

Utils

public class Utils {

    public static float dpToPixel(float dp) {
        DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
        return dp * metrics.density;
    }

}

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="执行动画" />

    <Button
        android:id="@+id/firstview"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:text="我是一个view" />

    <com.joanzapata.android.KeyframeView
        android:id="@+id/secondview"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_below="@+id/firstview"
        android:layout_marginTop="20dp" />
</LinearLayout>

代码:

public class MyActivityI extends AppCompatActivity implements View.OnClickListener {

    private Button mButton;
    private Button view1;
    private KeyframeView view2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anim);

        mButton = (Button) findViewById(R.id.btn);
        view1 = (Button) findViewById(R.id.firstview);
        view2 = (KeyframeView) findViewById(R.id.secondview);
        mButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        anim1();
        anim2();
    }

    private void anim2() {
        // 在 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(view2, holder);
        animator.setDuration(5000);
        animator.start();
    }

    /**
     * PropertyValuesHolder这个类可以先将动画属性和值暂时的存储起来,后一起执行,在有些时候可以使用替换掉AnimatorSet,减少代码量
     */
    private void anim1() {

        //keyframe
        Keyframe keyframe1 = Keyframe.ofFloat(0.0f, 0);
        Keyframe keyframe2 = Keyframe.ofFloat(0.25f, -30);
        Keyframe keyframe3 = Keyframe.ofFloat(0.5f, 30);
        Keyframe keyframe4 = Keyframe.ofFloat(1.0f, 0);
        PropertyValuesHolder rotation = PropertyValuesHolder.ofKeyframe(View.ROTATION, keyframe1, keyframe2, keyframe3, keyframe4);

        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.2f, 1.0f);
        PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.2f, 1.0f);
        PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.2f, 1.0f);

        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view1, alpha, scaleX, scaleY, rotation);
        animator.setInterpolator(new OvershootInterpolator());
        animator.setDuration(5000).start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值