Android动画之属性动画

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


一、属性动画单个动画

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;
        }
    }

}

执行效果:

旋转动画:


透明渐变动画:



二、属性动画的合集

添加以下方法,并在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()将动画顺序执行,当上一个动画没有结束时,下一个动画不会开始执行。

展示效果:



三、属性动画的监听

代码修改,添加动画运行更新监听,并在更新方法中刷新控件状态。使用了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();
    }
}

备注:

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

展示效果:



四、属性动画的应用

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

自定义控件实现如下:


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;
        }
    }
}

展示效果:



源码传送门



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


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



猜你喜欢

转载自blog.csdn.net/u013205623/article/details/78687862