欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android动画之属性动画

程序员文章站 2022-05-03 10:36:15
...

总归是逮着机会,稍微慢一点。在过去的很长一段时间内,都是在业务逻辑的复杂变化中挣扎。没有技术上的成长,内心还是蛮恐慌的。一不小心,又带有了些许的情绪在里面。。。。。


一、属性动画单个动画

1,布局文件添加动画作用目标


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.future.animatordemo.MainActivity">

    <ImageView
        android:id="@+id/content_iv"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:src="@mipmap/koala" />


</RelativeLayout>

2,获取控件并执行动画


public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    /**
     * 图片
     */
    private ImageView contentIV;

    /**
     * 自定义控件
     */
    private PointView createView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_bak);
        initView();
        initAnimation();
        initListener();
    }


    /**
     * 初始化控件
     */
    private void initView() {
        contentIV = findViewById(R.id.content_iv);
    }


    /**
     * 初始化动画
     */
    private void initAnimation() {
        rotateAnimation();
        //alpahAnimation();

    }

    private void initListener() {
        contentIV.setOnClickListener(this);
    }


    /**
     * 旋转动画
     */
    private void rotateAnimation() {
        ObjectAnimator anim = ObjectAnimator.ofFloat(contentIV, "rotation", 0f, 360f);
        anim.setDuration(1000);
        anim.start();
    }

    /**
     * 透明渐变动画
     */
    private void alpahAnimation() {
        ObjectAnimator anim = ObjectAnimator.ofFloat(contentIV, "alpha", 1.0f, 0.8f, 0.6f, 0.4f, 0.2f, 0.0f);
        anim.setRepeatCount(-1);
        anim.setRepeatMode(ObjectAnimator.REVERSE);
        anim.setDuration(2000);
        anim.start();
    }



    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.content_iv:
                Toast.makeText(MainActivity.this, "戳中朕心了~_~", Toast.LENGTH_SHORT).show();
                break;
        }
    }

}

执行效果:

旋转动画:

Android动画之属性动画

透明渐变动画:

Android动画之属性动画


二、属性动画的合集

添加以下方法,并在onCreate()中调用


    private void setAnimation() {
        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(contentIV, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);
        ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(contentIV, "scaleX", 0.0f, 1.0f);
        ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(contentIV, "scaleY", 0.0f, 2.0f, 1.0f);
        ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(contentIV, "rotation", 0, 360);
        ObjectAnimator transXAnim = ObjectAnimator.ofFloat(contentIV, "translationX", 100, 400);
        ObjectAnimator transYAnim = ObjectAnimator.ofFloat(contentIV, "translationY", 100, 750, 300, 600);
        AnimatorSet set = new AnimatorSet();
        set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);//叠加在一起运动
//        set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
        set.setDuration(3000);
        set.start();
    }

其中playTogether()将所有的动画组合在一起,同时开启动画。playSequentially()将动画顺序执行,当上一个动画没有结束时,下一个动画不会开始执行。

展示效果:

Android动画之属性动画


三、属性动画的监听

代码修改,添加动画运行更新监听,并在更新方法中刷新控件状态。使用了Layout()方法。


public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    /**
     * 图片
     */
    private ImageView contentIV;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initListener();
    }


    /**
     * 初始化控件
     */
    private void initView() {
        contentIV = findViewById(R.id.content_iv);
    }


    private void initListener() {
        contentIV.setOnClickListener(this);
    }


    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.content_iv:
                Toast.makeText(MainActivity.this, "戳中朕心了~_~", Toast.LENGTH_SHORT).show();
                break;
        }
    }

    public void startAnimatorAnimation(View view) {
        ValueAnimator animator = ValueAnimator.ofInt(0, 400);
        animator.setDuration(1000);
        animator.setInterpolator(new DecelerateInterpolator());

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int curValue = (int) animation.getAnimatedValue();
                contentIV.layout(curValue, curValue, curValue + contentIV.getWidth(), curValue + contentIV.getHeight());
            }
        });

        animator.setStartDelay(1000);
        animator.start();
    }
}

备注:

相比于补间动画,属性动画直接修改了控件属性。直接反馈就是点击事件在补间动画时,只有在控件开始的位置执行才有效,其他地方无效。而属性动画在运行过程中,控件所在位置就是响应事件响应位置。

展示效果:

Android动画之属性动画


四、属性动画的应用

依据以上学习内容,制作自定义控件,展示属性动画的应用。

自定义控件实现如下:


public class PointView extends View {

    public static final float RADIUS = 20f;

    private Point currentPoint;

    private Paint mPaint;
    private Paint linePaint;

    private AnimatorSet animSet;
    private TimeInterpolator interpolatorType = new LinearInterpolator();

    /**
     * 实现关于color 的属性动画
     */
    private int color;
    private float radius = RADIUS;

    public PointView(Context context) {
        super(context);
        init();
    }


    public PointView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PointView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }


    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
        mPaint.setColor(this.color);
    }

    public float getRadius() {
        return radius;
    }

    public void setRadius(float radius) {
        this.radius = radius;
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.TRANSPARENT);

        linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        linePaint.setColor(Color.BLACK);
        linePaint.setStrokeWidth(5);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point((int) RADIUS, (int) RADIUS);
            drawCircle(canvas);
        } else {
            drawCircle(canvas);
        }

        drawLine(canvas);
    }

    private void drawLine(Canvas canvas) {
        canvas.drawLine(10, getHeight() / 2, getWidth(), getHeight() / 2, linePaint);
        canvas.drawLine(10, getHeight() / 2 - 150, 10, getHeight() / 2 + 150, linePaint);
        canvas.drawPoint(currentPoint.x, currentPoint.y, linePaint);

    }

    public void startAnimation() {
        Point startP = new Point((int) RADIUS, (int) RADIUS);
//        Point endP = new Point(getWidth() - (int) RADIUS, getHeight() - (int) RADIUS);
        Point endP = new Point(MainApplication.getApplication().getWidth() - (int) RADIUS, MainApplication.getApplication().getHeight() - (int) RADIUS);
        final ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointSinEvaluator(), startP, endP);
        valueAnimator.setRepeatCount(-1);
        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                postInvalidate();
            }
        });

//
        ObjectAnimator animColor = ObjectAnimator.ofObject(this, "color", new ArgbEvaluator(), Color.GREEN,
                Color.YELLOW, Color.BLUE, Color.WHITE, Color.RED);
        animColor.setRepeatCount(-1);
        animColor.setRepeatMode(ValueAnimator.REVERSE);


        ValueAnimator animScale = ValueAnimator.ofFloat(20f, 80f, 60f, 10f, 35f, 55f, 10f);
        animScale.setRepeatCount(-1);
        animScale.setRepeatMode(ValueAnimator.REVERSE);
        animScale.setDuration(5000);
        animScale.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                radius = (float) animation.getAnimatedValue();
            }
        });


        animSet = new AnimatorSet();
        animSet.play(valueAnimator).with(animColor).with(animScale);
        animSet.setDuration(5000);
        animSet.setInterpolator(interpolatorType);
        animSet.start();

    }

    private void drawCircle(Canvas canvas) {
        float x = currentPoint.x;
        float y = currentPoint.y;
        canvas.drawCircle(x, y, radius, mPaint);
    }


    public void setInterpolatorType(int type) {
        switch (type) {
            case 1:
                interpolatorType = new BounceInterpolator();
                break;
            case 2:
                interpolatorType = new AccelerateDecelerateInterpolator();
                break;
            case 3:
                interpolatorType = new DecelerateInterpolator();
                break;
            case 4:
                interpolatorType = new AnticipateInterpolator();
                break;
            case 5:
                interpolatorType = new LinearInterpolator();
                break;
            case 6:
                interpolatorType = new LinearOutSlowInInterpolator();
                break;
            case 7:
                interpolatorType = new OvershootInterpolator();
            default:
                interpolatorType = new LinearInterpolator();
                break;
        }
    }


    @TargetApi(Build.VERSION_CODES.KITKAT)
    public void pauseAnimation() {
        if (animSet != null) {
            animSet.pause();
        }
    }


    public void stopAnimation() {
        if (animSet != null) {
            animSet.cancel();
            this.clearAnimation();
        }
    }
}

XML文件中使用:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.future.animatordemo.MainActivity">

    <ImageView
        android:id="@+id/content_iv"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:src="@mipmap/koala" />

    <com.future.animatordemo.view.PointView
        android:id="@+id/create_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />


</RelativeLayout>

初始化控件并使用控件:


public class MainActivityBak extends AppCompatActivity implements View.OnClickListener {
    /**
     * 图片
     */
    private ImageView contentIV;

    /**
     * 自定义控件
     */
    private PointView createView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_bak);
        initView();
        initAnimation();
        initListener();
    }


    /**
     * 初始化控件
     */
    private void initView() {
        contentIV = findViewById(R.id.content_iv);
        createView = findViewById(R.id.create_view);
    }


    /**
     * 初始化动画
     */
    private void initAnimation() {
        setAnimation();
        createView.startAnimation();
    }

    private void initListener() {
        contentIV.setOnClickListener(this);
    }




    private void setAnimation() {
        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(contentIV, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);
        ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(contentIV, "scaleX", 0.0f, 1.0f);
        ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(contentIV, "scaleY", 0.0f, 2.0f, 1.0f);
        ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(contentIV, "rotation", 0, 360);
        ObjectAnimator transXAnim = ObjectAnimator.ofFloat(contentIV, "translationX", 100, 400);
        ObjectAnimator transYAnim = ObjectAnimator.ofFloat(contentIV, "translationY", 100, 750, 300, 600);
        AnimatorSet set = new AnimatorSet();
        set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);//叠加在一起运动
//        set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
        set.setDuration(3000);
        set.start();
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.content_iv:
                Toast.makeText(MainActivity.this, "戳中朕心了~_~", Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

展示效果:

Android动画之属性动画


源码传送门



有人请教我哆啦A梦和大雄最后有没有在一起,我便问他,许仙最后有没有和白蛇在一起。生之有涯‘最后'如何,也不过是蜿蜒个几十年的一件小事,而大事是他们,和我们曾经在一起过。 


所有被千夫所指的困难,都是为了淘汰掉懦夫!