Android权威编程指南笔记 第三十二章 属性动画

文章目录

  • 第三十二章 属性动画
    • 属性动画
    • 创造动画集
    • 属性转化
    • 相关小记(未完)
    • 挑战练习

第三十二章 属性动画

属性动画

  • 属性动画的使用
        final ObjectAnimator sunsetSkyAnimator = ObjectAnimator //属性动画的制作对象
                .ofInt(mSkyView, "backgroundColor", //特征名, 如: setX. 也可以在自定义view中设置
                        mBuleSkyColor, mSunsetSkyColor)// 颜色的起始值
                .setDuration(3000); // 动画进行的时间
        sunsetSkyAnimator.setEvaluator(new ArgbEvaluator());
        /*这里是一个求值程序,求颜色递增值。起到协助作用*/
  • 实现不同的动画特效
    heightAnimation.setInterpolator(new AccelerateInterpolator());//这里是加速的动画特效

创造动画集

  • 动画集的使用
		animatorSet1 = new AnimatorSet();
        animatorSet1
                .play(heightAnimation)
                .with(sunsetSkyAnimator)
                .with(pointRadius)
                .before(nightSkyAnimator);
        animatorSet1.start(); //启动动画集
        animatorSet1.pause(); //暂停动画集
  • 动画集的事件监听
    1.监听动画的起始
    AnimatorSet.addListener(new AnimatorListenerAdapter(){});中的方法进行实现
  1. 监听动画的暂停
    实现AnimatorSet.addPauseListener(new Animator.AnimatorPauseListener(){})中的相关方法

属性转化

  • 旋转视图
    rotation, privoteX, privoteY
  • 缩放视图
    scaleX, scaleY
  • 移动视图
    translationX, translationY
  • 以上每个属性都有各自的setter和getter方法.

相关小记(未完)

  • 视图转场框架
    实现布局动态转场任务

挑战练习

  • 再次点击屏幕, 让太阳上升
  • 利用setRepeatCount(Int)实现太阳的有规律的放大缩小
  • 在下落过程中点击后无缝回升到原来的位置
  • 由于各种细节太过于麻烦, 以上的功能都实现了, 但整体不够好 ( Orz )
    无缝回升需要API版本大于26
  • SunsetFragment.java
package com.bignerdranch.andriod.sunset;


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;

/**
 * A simple {@link Fragment} subclass.
 */
public class SunsetFragment extends Fragment {
    private View mSceneview;
    private View mSunView;
    private View mSkyView;
    private int mBuleSkyColor;
    private int mSunsetSkyColor;
    private int mNightSkyColor;
    public static float width;
    public static float height;
    private int i = 0;//向下动画运行完,i+1。向上动画则相反
    private AnimatorSet animatorSet1;
    private AnimatorSet animatorSet2;
    private float mSunViewTop; //初始太阳位置
    private float mSkyViewBottom; //初始太阳结束位置
    private float currentSunViewTop; // 当前太阳位置
    private int currentSunsetSky; // 当前背景颜色
    private int currentNightSky; // 当前夜晚颜色
    private long currentTime; // 当前动画时间
    private static final String TAG = "SunsetFragment";

    public static SunsetFragment newInstance(){
        return new SunsetFragment();
    }



    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_sunset, container, false);

        mSceneview = view;
        mSunView = view.findViewById(R.id.sun);
        mSkyView = view.findViewById(R.id.sky);


        Resources resources = getResources();
        mBuleSkyColor = resources.getColor(R.color.blue_sky);
        mSunsetSkyColor = resources.getColor(R.color.sunset_sky);
        mNightSkyColor = resources.getColor(R.color.night_sky);

        view.post(new Runnable() { //由于fragment在最开始无法获取相关view的属性
            @Override
            public void run() {
                width = mSkyView.getWidth();
                height = mSkyView.getHeight();自动得知

                mSunViewTop = mSunView.getY();
                mSkyViewBottom = mSkyView.getBottom();

                currentSunViewTop = mSunView.getTop();
                Log.i(TAG, " 你当前位置是 " + currentSunViewTop);
                Log.i(TAG, " 底部位置是 " + mSkyViewBottom);
            }
        });


        mSceneview.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (currentSunViewTop == mSunViewTop && i == 0) {
                    //启动向下动画,i = 1
                    startAnimation1(mSunViewTop);

                }else if (currentSunViewTop == mSkyViewBottom && i == 1){
                    //启动向上动画]
                    startAnimation2(mSkyViewBottom, mSunsetSkyColor,
                            mNightSkyColor, 3200);
                }else {
                    if (i == 1){
                        //向下动画时,实现向上无缝衔接反向动画
                        animatorSet1.pause();
                        startAnimation2(currentSunViewTop, currentSunsetSky,
                                currentNightSky, currentTime);
                    }
//                    else if (){
//                        //此处省略了向上动画的反向无缝衔接
//                    }
                }
            }
        });
        return view;
    }


    //启动向下动画
    private void startAnimation1(float sunViewTop){

        ObjectAnimator heightAnimation = ObjectAnimator
                .ofFloat(mSunView, "y", sunViewTop, mSkyViewBottom)
                /*关于这里的特征名需要查看相关文档*/
                .setDuration(3200);
        heightAnimation.setInterpolator(new AccelerateInterpolator());

        @SuppressLint("ObjectAnimatorBinding")
        ObjectAnimator pointRadius = ObjectAnimator
                .ofInt(mSunView, "PointRadius",
                        100, 150, 100)
                .setDuration(3200);
        pointRadius.setRepeatCount(1);

        final ObjectAnimator sunsetSkyAnimator = ObjectAnimator
                .ofInt(mSkyView, "backgroundColor",
                        mBuleSkyColor, mSunsetSkyColor)
                .setDuration(3000);
        sunsetSkyAnimator.setEvaluator(new ArgbEvaluator());
        /*这里是一个求值程序,求颜色递增值。起到协助作用*/

        final ObjectAnimator nightSkyAnimator = ObjectAnimator
                .ofInt(mSkyView, "backgroundColor",
                        mSunsetSkyColor, mNightSkyColor)
                .setDuration(1500);
        nightSkyAnimator.setEvaluator(new ArgbEvaluator());


        animatorSet1 = new AnimatorSet();
        animatorSet1.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                currentSunViewTop = mSunView.getY();
                Log.i(TAG, " animatorSet1 初始位置是 " + currentSunViewTop);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                currentSunViewTop = mSunView.getY();
                Log.i(TAG, " animatorSet1 结束位置是 " + currentSunViewTop);
            }
        });


        //将向下状态的值作为保留,给animator2
        animatorSet1.addPauseListener(new Animator.AnimatorPauseListener() {
            @Override
            public void onAnimationPause(Animator animation) {
                currentSunViewTop = mSunView.getY();
                currentSunsetSky = (int) sunsetSkyAnimator.
                        getAnimatedValue("backgroundColor");
                currentNightSky = (int) nightSkyAnimator.
                        getAnimatedValue("backgroundColor");
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    currentTime = animatorSet1.getCurrentPlayTime();
                }
                Log.i(TAG, " animatorSet1 暂停位置是 " + currentSunViewTop);
                Log.i(TAG, " animatorSet1 暂停位置的颜色是 " + currentSunsetSky);
                Log.i(TAG, " animatorSet1 暂停位置的夜间颜色是 " + currentNightSky);
                Log.i(TAG, " animatorSet1 暂停位置的时间是 " + currentTime);
            }

            @Override
            public void onAnimationResume(Animator animation) {

            }
        });

        animatorSet1
                .play(heightAnimation)
                .with(sunsetSkyAnimator)
                .with(pointRadius)
                .before(nightSkyAnimator);
        animatorSet1.start();
        i++;
    }


    //启动向上动画
    private void startAnimation2(float currentSunViewTop,int currentSunsetSky,
                                 int currentNightSky, long currentTime){
        @SuppressLint("ObjectAnimatorBinding")
        ObjectAnimator pointRadius = ObjectAnimator
                .ofInt(mSunView, "PointRadius",
                        100, 100)
                .setDuration(currentTime);

        ObjectAnimator heightAnimation = ObjectAnimator
                .ofFloat(mSunView, "y", currentSunViewTop, mSunViewTop)
                .setDuration(currentTime);
        heightAnimation.setInterpolator(new AccelerateInterpolator());

        ObjectAnimator sunUpSkyAnimator = ObjectAnimator
                .ofInt(mSkyView, "backgroundColor",
                        currentSunsetSky, mBuleSkyColor)
                .setDuration(currentTime);
        sunUpSkyAnimator.setEvaluator(new ArgbEvaluator());


        animatorSet2 = new AnimatorSet();
        animatorSet2.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                SunsetFragment.this.currentSunViewTop = mSunView.getY();
                Log.i(TAG, " animatorSet2 开始位置是 " +
                        SunsetFragment.this.currentSunViewTop);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                SunsetFragment.this.currentSunViewTop = mSunView.getY();
                Log.i(TAG, " animatorSet2 结束位置是 " +
                        SunsetFragment.this.currentSunViewTop);
            }
        });

        if (currentTime > 3200){
            ObjectAnimator nightSkyAnimator = ObjectAnimator
                    .ofInt(mSkyView, "backgroundColor",
                            currentNightSky, mSunsetSkyColor)
                    .setDuration(currentTime - 3200);
            nightSkyAnimator.setEvaluator(new ArgbEvaluator());

            animatorSet2
                    .play(heightAnimation)
                    .with(sunUpSkyAnimator)
                    .with(pointRadius)
                    .after(nightSkyAnimator);
        }else if (currentTime == 3200){
            ObjectAnimator nightSkyAnimator = ObjectAnimator
                    .ofInt(mSkyView, "backgroundColor",
                            mNightSkyColor, mSunsetSkyColor)
                    .setDuration(1500);
            nightSkyAnimator.setEvaluator(new ArgbEvaluator());

            animatorSet2
                    .play(heightAnimation)
                    .with(sunUpSkyAnimator)
                    .after(nightSkyAnimator);
        }else {
            animatorSet2
                    .play(heightAnimation)
                    .with(pointRadius)
                    .with(sunUpSkyAnimator);
        }
        animatorSet2.start();
        i--;
    }

}

  • 自定义的view视图MyPointView.java
package com.bignerdranch.andriod.sunset;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

public class MyPointView extends View {
    private Paint paint;
    private Point mPoint = new Point(100);

    public MyPointView(Context context) {
        this(context, null);
    }

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

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.YELLOW);
        paint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mPoint != null){
            canvas.drawCircle(SunsetFragment.width/2,SunsetFragment.height/2,
                    mPoint.getRadius(), paint);
        }
    }
    //自定义的set方法, 用于特征名的设置
    public void setPointRadius(int radius){
        mPoint.setRadius(radius);
        invalidate();
    }
}

  • fragment_sunset.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <FrameLayout
        android:id="@+id/sky"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.61"
        android:background="@color/blue_sky">

        <com.bignerdranch.andriod.sunset.MyPointView
            android:id="@+id/sun"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"/>
    FrameLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.39"
        android:background="@color/sea"/>

LinearLayout>

  • Point.java
package com.bignerdranch.andriod.sunset;

public class Point {
    private  int mRadius;

    public Point(int radius){
        mRadius = radius;
    }

    public int getRadius() {
        return mRadius;
    }

    public void setRadius(int radius) {
        mRadius = radius;
    }
}

你可能感兴趣的:(Android权威编程指南笔记 第三十二章 属性动画)