Android炫酷应用300例读书笔记五_2

130.使用ValueAnimator实现分段转圈动画

public class AnimImageView extends View {
    private Paint mPaint;
    private Path mPath;
    private Path mNewPath;
    private PathMeasure mPathMeasure;
    private ValueAnimator mValueAnimator;
    private float mAnimatedValue;
    private float mLength;
    public AnimImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPathMeasure = new PathMeasure();
        mPaint= new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(25);
        mPaint.setColor(Color.BLUE);
        mPath = new Path();
        mPath.addCircle(250,300,200, Path.Direction.CW);
        mPathMeasure.setPath(mPath,true);
        mLength = mPathMeasure.getLength();
        mNewPath = new Path();

        mValueAnimator = ValueAnimator.ofFloat(0,1);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mAnimatedValue = (float) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mValueAnimator.setDuration(2000);
        mValueAnimator.start();
    }


    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        canvas.translate(250,500);
        mNewPath.reset();
        mNewPath.lineTo(0,0);
        float stop = mLength * mAnimatedValue;
        float start = (float) (stop - ( (0.5- Math.abs(mAnimatedValue - 0.5)) * mLength) );
        mPathMeasure.getSegment(start,stop,mNewPath,true);
        canvas.drawPath(mNewPath,mPaint);
    }
}
<LinearLayout
    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"
    android:orientation="vertical">

    <com.cc.uisample.AnimImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>
public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";

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

}

131.使用ValueAnimator在三维Z轴上平移图像
这里的知识点是z轴和ValueAnimator的使用。
数学中的三维坐标图如下所示。


数学中的坐标
android中的坐标

在5.0之前,我们的视图都是二维的,只有x轴和y轴,现在,android新增了z轴。x轴和y轴描述了一个view的大小和位置,而z轴描述了view在父视图上抬起的视觉,体现效果就是阴影。View的Z属性可以通过elevation和translationZ进行修改。
z = elevation+translationZ
参考链接:
Android 5.0 新特性
https://www.cnblogs.com/baiqiantao/p/6243118.html

z轴具体效果可以看官网链接:
官网介绍:
Elevation
https://material.io/design/environment/elevation.html

<LinearLayout
    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"
    android:orientation="vertical"
    android:gravity="center">

    <ImageView
        android:id="@+id/image_view"
        android:src = "@drawable/test"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>
public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";
    private ValueAnimator mValueAnimator;
    private float mAnimatedValue;
    private ImageView mImageView;
    private Bitmap mNewBitmap;
    private Camera mCamera;//android.graphics.Camera



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.image_view);
        mCamera = new Camera();
        mValueAnimator = ValueAnimator.ofFloat(0,900);
        mValueAnimator.setDuration(3000);
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mValueAnimator.setRepeatMode(ValueAnimator.REVERSE);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mAnimatedValue = (float) valueAnimator.getAnimatedValue();
                mNewBitmap = getNewBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.test),mAnimatedValue);
                mImageView.setImageBitmap(mNewBitmap);
            }
        });
        mValueAnimator.start();
    }

    private Bitmap getNewBitmap(Bitmap bitmap,float animatedValue){
        mCamera.save();
        Matrix matrix = new Matrix();
        mCamera.translate(0,0,animatedValue);
        mCamera.getMatrix(matrix);
        mCamera.restore();
        //设置图像处理的中心点
        matrix.preTranslate(bitmap.getWidth() >> 1,bitmap.getHeight() >> 1);
        return Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),
                matrix,true);//通过矩阵生成新图像
    }

参考链接:
Android自定义控件之3D上下翻页效果的倒计时控件
https://blog.csdn.net/android_cmos/article/details/70477285

延伸:
Android应用坐标系统全面详解
https://blog.csdn.net/yanbober/article/details/50419117/

132.使用ValueAnimator实现起飞转平飞动画
首先,百度找一个图标。


plane
<android.support.constraint.ConstraintLayout
    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"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="90dp"
        android:layout_height="75dp"
        android:src="@drawable/plane"
        android:layout_marginLeft="16dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="29dp"/>
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";
    private ValueAnimator mValueAnimator;
    private ImageView mImageView;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.image_view);
        //逆时针旋转30°,设置起飞
        mImageView.setRotation(-30);
        PointF startPoint = new PointF(0,1400);
        PointF middlePoint = new PointF(400,300);
        PointF endPoint = new PointF(700,300);
        TypeEvaluator<PointF> typeEvaluator = new TypeEvaluator<PointF>() {
            @Override
            public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
                float x = startValue.x + fraction * (endValue.x - startValue.x);
                float y = startValue.y + fraction * (endValue.y - startValue.y);
                //当y值到达300,图像保持水平
                if (y == 300){
                    mImageView.setRotation(0);
                }
                return  new PointF(x,y);
            }
        };
        //运动飞行路径为startPoint 、middlePoint和endPoint连成的折现
        mValueAnimator = ValueAnimator.ofObject(typeEvaluator,startPoint,middlePoint,endPoint);
        mValueAnimator.setDuration(5000);
        mValueAnimator.setInterpolator(new DecelerateInterpolator());
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mValueAnimator.setRepeatMode(ValueAnimator.REVERSE);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //根据变化的路径设置mImageView的坐标
                PointF currentPoint = (PointF) valueAnimator.getAnimatedValue();
                mImageView.setX(currentPoint.x);
                mImageView.setY(currentPoint.y);
            }
        });
        mValueAnimator.start();
    }

}

133.自定义TypeEvaluator以GIF动画显示图像
GIF的本质其实是一系列图片的组合。
所以先找一个gif,然后用在线工具,把gif分解。


gif

下面的分解后的前5张图片。


dog_1.jpg
dog_2.jpg
dog_3.jpg
dog_4.jpg
dog_5.jpg

把这几张放到drawable中。

<android.support.constraint.ConstraintLayout
    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"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="208dp"
        android:layout_height="318dp"
        android:src="@drawable/dog_1"
        android:layout_marginLeft="101dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="133dp"/>
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";
    private ValueAnimator mValueAnimator;
    private ImageView mImageView;

    private int[] mImages = {R.drawable.dog_1,R.drawable.dog_2,R.drawable.dog_3,
            R.drawable.dog_4,R.drawable.dog_5};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.image_view);
        //图像数组索引从0到4
        mValueAnimator = ValueAnimator.ofObject(new MyTypeEvaluator(),0,4);
        mValueAnimator.setDuration(500);// 500ms
        mValueAnimator.setInterpolator(new DecelerateInterpolator());
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mValueAnimator.setRepeatMode(ValueAnimator.REVERSE);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int index = (int) valueAnimator.getAnimatedValue();
                //根据时间线确定索引图像
                mImageView.setImageResource(mImages[index]);

            }
        });
        mValueAnimator.start();
    }

    public class MyTypeEvaluator implements TypeEvaluator<Integer>{

        @Override
        public Integer evaluate(float v, Integer start, Integer end) {
            return  (int) (start + v * (end - start));
        }
    }


}

134.使用Animation实现图像围绕自身中心旋转
知识点是Android 旋转动画。书上用的是RotateAnimation 去实现的。
可以参考这里。
Android旋转动画rotate动画,xml配置set实现
https://blog.csdn.net/zhangphil/article/details/77163138

这里有一个用ObjectAnimator实现的。
android 实现可暂停的旋转动画效果
https://www.jianshu.com/p/52abfdeb1c38

先在res下面创建anim目录,然后再res/anim下面创建一个自命名的动画属性配置文件假如叫做rotate_anim.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <rotate
        android:duration="1000"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="infinite"
        android:interpolator="@android:anim/linear_interpolator"
        android:toDegrees="360" />
</set>

xml

<android.support.constraint.ConstraintLayout
    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"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="208dp"
        android:layout_height="318dp"
        android:src="@drawable/dog_1"
        android:layout_marginLeft="101dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="133dp"/>
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";
     private ImageView mImageView;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.image_view);
        Animation rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate_anim);
        mImageView.startAnimation(rotateAnimation);
    }

}

但是rotate_anim.xml部分其实也可以用java的方式去实现的,具体参考下面的链接。
android旋转动画的两种实现方式https://www.cnblogs.com/llguanli/p/8674274.html

参考链接:
安卓动画实现一边绕自身中心旋转一边移动所遇见的问题
https://blog.csdn.net/Mai_NO/article/details/79715142

135.自定义Animation实现旋转切换扑克牌正反面
书上主要是用到了Matrix 和Camera,以及Rotate3dAnimation。Rotate3dAnimation是官方的api demo中给出的,一般都是在此基础上去修改使用。
这个链接原理部分介绍的非常详细。
安卓自定义View进阶-Matrix Camera
http://www.gcssloop.com/customview/matrix-3d-camera

众所周知,我们的手机屏幕是一个2D的平面,所以也没办法直接显示3D的信息,因此我们看到的所有3D效果都是3D在2D平面的投影而已,而本文中的Camera主要作用就是这个,将3D信息转换为2D平面上的投影,实际上这个类更像是一个操作Matrix的工具类,使用Camera和Matrix可以在不使用OpenGL的情况下制作出简单的3D效果。
出自http://www.gcssloop.com/customview/matrix-3d-camera

实现版本可以参考这个。
翻牌(翻转)动画-Rotate3dAnimation的应用
https://www.jianshu.com/p/6f765834d471

首先,链接给出了2张卡片图。这个貌似是塔罗牌?


dark.jpeg
light.jpeg
public class Rotate3dAnimation extends Animation {
    private final float mFromDegrees;
    private final float mToDegrees;
    private final float mCenterX;
    private final float mCenterY;
    private final float mDepthZ;
    private final boolean mReverse;
    private Camera mCamera;
    float scale = 1;    // <------- 像素密度

    /**
     * 创建一个绕y轴旋转的3D动画效果,旋转过程中具有深度调节,可以指定旋转中心。
     * @param context     <------- 添加上下文,为获取像素密度准备
     * @param fromDegrees 起始时角度
     * @param toDegrees   结束时角度
     * @param centerX     旋转中心x坐标
     * @param centerY     旋转中心y坐标
     * @param depthZ      最远到达的z轴坐标
     * @param reverse     true 表示由从0到depthZ,false相反
     */
    public Rotate3dAnimation(Context context, float fromDegrees, float toDegrees,
                             float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;

        // 获取手机像素密度 (即dp与px的比例)
        scale = context.getResources().getDisplayMetrics().density;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;
        final Matrix matrix = t.getMatrix();
        camera.save();

        // 调节深度
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }

        // 绕y轴旋转
        camera.rotateY(degrees);

        camera.getMatrix(matrix);
        camera.restore();

        // 修正失真,主要修改 MPERSP_0 和 MPERSP_1
        float[] mValues = new float[9];
        matrix.getValues(mValues);              //获取数值
        mValues[6] = mValues[6]/scale;          //数值修正
        mValues[7] = mValues[7]/scale;          //数值修正
        matrix.setValues(mValues);              //重新赋值

        // 调节中心点
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}
<android.support.constraint.ConstraintLayout
    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"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="208dp"
        android:layout_height="318dp"
        android:src="@drawable/light"
        android:layout_marginLeft="101dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="133dp"/>
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";
    private ImageView mImageView;
    private boolean isDark = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.image_view);
        mImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //用post方法取card的宽高
                mImageView.post(new Runnable() {
                    @Override
                    public void run() {
                        //取card中心点
                        final float centerX = mImageView.getWidth() / 2f;
                        final float centerY = mImageView.getHeight() / 2f;
                        // 构建3D旋转动画对象,旋转角度为0到90度
                        final Rotate3dAnimation rotation = new Rotate3dAnimation(MainActivity.this, 0, 90, centerX, centerY,
                                0f, false);
                        // 动画持续时间500毫秒
                        rotation.setDuration(500);
                        // 动画完成后保持完成的状态
                        rotation.setFillAfter(true);
                        rotation.setInterpolator(new AccelerateInterpolator());
                        mImageView.startAnimation(rotation);
                        //监听器  翻转到90度的时候 卡面图片改变 然后将卡牌从270度翻转到360度刚好转回来
                        //这里注意不是90-180度,因为90-180翻转过来的图片是左右相反的镜像图
                        rotation.setAnimationListener(new Animation.AnimationListener() {
                            @Override
                            public void onAnimationStart(Animation animation) {
                            }

                            @Override
                            public void onAnimationEnd(Animation animation) {
                                //正反面判断
                                if (isDark) {
                                    isDark = false;
                                } else {
                                    isDark = true;
                                }
                                //点正面切换背面,反之亦然
                                if (isDark) {
                                   // Glide.with(MainActivity.this).load(R.drawable.light).into(card);
                                    mImageView.setImageResource(R.drawable.light);
                                } else {
                                  //  Glide.with(MainActivity.this).load(R.drawable.dark).into(card);
                                    mImageView.setImageResource(R.drawable.dark);

                                }
                                //270度翻转到360度
                                final Rotate3dAnimation rotation = new Rotate3dAnimation(MainActivity.this, 270, 360, centerX, centerY,
                                        0f, true);
                                rotation.setDuration(500);
                                // 动画完成后保持完成的状态
                                rotation.setFillAfter(false);
                                mImageView.startAnimation(rotation);
                            }

                            @Override
                            public void onAnimationRepeat(Animation animation) {
                            }
                        });

                    }
                });
            }
        });
    }

}

136.使用AnimationSet实现组合多个不同的动画
这里与前面的126.使用AnimatorSet组合多个ObjectAnimator
差异在于这里用的是playTogether。

//126小节
mAnimatorSet.play(mObjectAnimator1).with(mObjectAnimator2).
                with(mObjectAnimator3).with(mObjectAnimator4);
mAnimatorSet.playTogether(mObjectAnimator1,mObjectAnimator2,mObjectAnimator3,mObjectAnimator4);

There are two different approaches to adding animations to a AnimatorSet: either the AnimatorSet#playTogether(Animator[]) or AnimatorSet#playSequentially(Animator[]) methods can be called to add a set of animations all at once, or the AnimatorSet#play(Animator) can be used in conjunction with methods in the AnimatorSet.Builder class to add animations one by one.

https://developer.android.google.cn/reference/android/animation/AnimatorSet.html?hl=en#playTogether(android.animation.Animator...)

137.使用Animation实现按照顺序显示网格Item
书上的例子是通过使用GridLayoutAnimationController,按照一定的顺序,调节GridView每个Item的透明度控制显示效果的。
看这个就行了。
自定义控件三部曲之动画篇(十一)——layoutAnimation与gridLayoutAnimation
https://blog.csdn.net/harvic880925/article/details/50785786

138.使用windowAnimations实现缩放对话框窗口
对话框的实现参考这篇即可。
动画对话框实现
https://blog.csdn.net/duihuapixiu/article/details/101050339
上篇的动画效果并不是缩放,缩放部分参考这篇。

安卓简单实现自定义对话框
https://blog.csdn.net/huidev/article/details/80213197

scale_in.xml 代码

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="100">
    <scale
        android:fromXScale="50%"
        android:fromYScale="50%"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="100%"
        android:toYScale="100%"/>
</set>

scale_out.xml 代码

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="160">
    <scale
        android:fromXScale="100%"
        android:fromYScale="100%"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="20%"
        android:toYScale="20%"/>
</set>

139.使用AnimationDrawable播放多幅图像
这里是AnimationDrawable的一个基本使用。这里是用纯java方式去实现的。

public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";
    private ImageView mImageView;
     private AnimationDrawable mAnimationDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.image_view);
        mAnimationDrawable = new AnimationDrawable();
        Drawable drawable1 =  ResourcesCompat.getDrawable(getResources(), R.drawable.dog_1, null);
        Drawable drawable2 =  ResourcesCompat.getDrawable(getResources(), R.drawable.dog_2, null);
        Drawable drawable3 =  ResourcesCompat.getDrawable(getResources(), R.drawable.dog_3, null);
        Drawable drawable4 =  ResourcesCompat.getDrawable(getResources(), R.drawable.dog_4, null);
        Drawable drawable5 =  ResourcesCompat.getDrawable(getResources(), R.drawable.dog_5, null);
        //添加图片到AnimationDrawable,并设定显示时长
        mAnimationDrawable.addFrame(drawable1,100);
        mAnimationDrawable.addFrame(drawable2,100);
        mAnimationDrawable.addFrame(drawable3,200);
        mAnimationDrawable.addFrame(drawable4,200);
        mAnimationDrawable.addFrame(drawable5,300);

        mAnimationDrawable.setOneShot(false);//一直播放该动画
        mImageView.setImageDrawable(mAnimationDrawable);
        mAnimationDrawable.start();
    }

}
<android.support.constraint.ConstraintLayout
    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"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="208dp"
        android:layout_height="318dp"
        android:src="@drawable/dog_1"
        android:layout_marginLeft="101dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="133dp"/>
</android.support.constraint.ConstraintLayout>

140.使用AnimationDrawable创建动画
这里的知识点其实是在指定地方播放帧动画。
可参考这里:
8.4.1 Android动画合集之帧动画
https://www.runoob.com/w3cnote/android-tutorial-animation.html

141.使用RotateAnimation实现围绕自身中心旋转
这里与前面的134.使用Animation实现图像围绕自身中心旋转的差异在于,134小节使用的是xml+java方式去实现,这里是纯java方式实现的。

<android.support.constraint.ConstraintLayout
    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"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="208dp"
        android:layout_height="318dp"
        android:src="@drawable/dog_1"
        android:layout_marginLeft="101dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="133dp"/>
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";
    private ImageView mImageView;
    private RotateAnimation mRotateAnimation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.image_view);
        mRotateAnimation = new RotateAnimation(
                0 //fromDegrees起始角度
                , 360 //toDegrees旋转角度
                , Animation.RELATIVE_TO_SELF, 0.5f,//pivotXType 旋转中心的X轴
                //RELATIVE_TO_SELF:相对自身
                Animation.RELATIVE_TO_SELF, 0.5f//pivotXValue 旋转中心的Y轴
        );
        mRotateAnimation.setDuration(1000);
        mRotateAnimation.setRepeatCount(Animation.INFINITE);
        mImageView.setAnimation(mRotateAnimation);
        mRotateAnimation.startNow();
    }

}

参考链接:
RotateAnimation旋转动画Demo

142.使用AlphaAnimation创建淡入淡出动画
知识点是AlphaAnimation的使用。

//淡入
AlphaAnimation alphaAnimation1 = new AlphaAnimation(0.0f, 1.0f);
//淡出
AlphaAnimation alphaAnimation2 = new AlphaAnimation(1.0f, 0.0f);

参考链接:
Android 动画 - AlphaAnimation渐变动画
https://blog.csdn.net/shibin1990_/article/details/51602498

143.使用ScaleAnimation创建缩放图像动画
参考链接:
Android 动画 - ScaleAnimation 缩放动画使用(附图)
https://blog.csdn.net/shibin1990_/article/details/51603910

其实这些都是补间动画,通过使用Animation对单个图像执行一系列转换来创建动画。

144.在ViewPager中实现上下滑动的转场动画
这里是使用了PageTransformer 。
从使用习惯上来说,一般ViewPager是用于横向的界面切换,这里改成了上下滑动转场。

public class VerticalPageTransformer implements  ViewPager.PageTransformer {

    @Override
    public void transformPage(View page, float position) {
        if (position <= 1){
            page.setTranslationX(page.getWidth() * -position);
            float myPosition = position * page.getHeight();
            page.setTranslationY(myPosition);//在垂直方向上平移图像
        }
    }
}

最后调用ViewPager.setPageTransformer(true, new VerticalPageTransformer());就会生效。
参考链接:
ViewPager切换动画PageTransformer使用

PageTransformer使用及注意
https://blog.csdn.net/ccc905341846/article/details/50947852

Android ViewPager.PageTransformer详解
https://www.jianshu.com/p/3a199fbe1f7f

145.通过下拉手指实现两个Activity的相互切换
这里的主要知识点是android 手势监听。

public class MainActivity extends AppCompatActivity{
    //手指按下的点为(x1, y1)手指离开屏幕的点为(x2, y2)
    private float x1 = 0;
    private float x2 = 0;
    private float y1 = 0;
    private float y2 = 0;

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //继承了Activity的onTouchEvent方法,直接监听点击事件
        if(event.getAction() == MotionEvent.ACTION_DOWN) {
            //当手指按下的时候
            x1 = event.getX();
            y1 = event.getY();
        }
        if(event.getAction() == MotionEvent.ACTION_UP) {
            //当手指离开的时候
            x2 = event.getX();
            y2 = event.getY();
            if(y1 - y2 > 50) {
                Toast.makeText(MainActivity.this, "向上滑", Toast.LENGTH_SHORT).show();
            } else if(y2 - y1 > 50) {
                Toast.makeText(MainActivity.this, "向下滑", Toast.LENGTH_SHORT).show();
            } else if(x1 - x2 > 50) {
                Toast.makeText(MainActivity.this, "向左滑", Toast.LENGTH_SHORT).show();
            } else if(x2 - x1 > 50) {
                Toast.makeText(MainActivity.this, "向右滑", Toast.LENGTH_SHORT).show();
            }
        }
        return super.onTouchEvent(event);
    }

}

参考链接:
Android笔记:android监听手势上下滑动
https://blog.csdn.net/xiaoyu940601/article/details/62218224

146.在应用启动时使用进场动画启动Activity
知识点是overridePendingTransition的使用。

public class MainActivity extends AppCompatActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        overridePendingTransition(R.anim.enter, R.anim.exit);
        setContentView(R.layout.activity_main);
    }


}

exit

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:duration="5000"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="0.0"
        android:toYScale="0.0" />
</set>

enter

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:duration="5000"
        android:fromXScale="0.0"
        android:fromYScale="0.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.0"
        android:toYScale="1.0" />
</set>

147.以左入右出的动画效果切换两个Activity
148.以收缩扩张的动画效果切换两个Activity
147和148合并,参考这个。
参考链接:
Android Activity切换动画overridePendingTransition
https://blog.csdn.net/bufanni12/article/details/26453725
进入动画

startActivity(intent);
overridePendingTransition(android.R.anim.xx, android.R.anim.xx);

退出动画

finish();
overridePendingTransition(android.R.anim.xx, android.R.anim.xx);

149.使用转场动画Explode切换两个Activity
这里是用来package android.transition中Explode类。这个类实现了进入第二个activity图片会聚合到一起的效果,以及退出时图片散开。
MainActivity

public class MainActivity extends AppCompatActivity{
    private Button mButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (Button) findViewById(R.id.button);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this,Main2Activity.class);
                startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this).toBundle());
            }
        });
    }

}

activity_main.xml

<android.support.constraint.ConstraintLayout
    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"
    android:orientation="vertical">
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        android:layout_marginLeft="137dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="38dp"/>


</android.support.constraint.ConstraintLayout>

Main2Activity

public class Main2Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        //进场动画
        getWindow().setEnterTransition(new Explode().setDuration(2000));
        //退场动画
        getWindow().setExitTransition(new Explode().setDuration(2000));

    }
}

activity_main2.xml

<android.support.constraint.ConstraintLayout
    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.cc.uisample.Main2Activity">
    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="131dp"
        android:layout_height="134dp"
        android:layout_marginRight="192dp"
        android:layout_marginTop="278dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/image1"/>

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="131dp"
        android:layout_height="134dp"
        android:layout_marginRight="192dp"
        android:layout_marginTop="144dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/image1"/>



    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="131dp"
        android:layout_height="134dp"
        app:srcCompat="@mipmap/image1"
        android:layout_marginRight="61dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="144dp"/>

    <ImageView
        android:id="@+id/imageView4"
        android:layout_width="131dp"
        android:layout_height="134dp"
        android:layout_marginRight="61dp"
        android:layout_marginTop="278dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/image1"/>
</android.support.constraint.ConstraintLayout>

参考链接:
Activity转场动画
https://www.jianshu.com/p/ea53d2f03cfd

Android动画之场景变换Transition动画的使用
https://www.jianshu.com/p/09834d89e733

150.使用转场动画Slide切换两个Activity
其余部分和149小节保持一致,修改Main2Activity 中的部分。
Slide,滑动。
slideEdge:表示从哪边进入或退出取值有left|top|right|bottom|。

public class Main2Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        Slide slide = new Slide();
        slide.setDuration(2000);
        slide.setSlideEdge(Gravity.RIGHT);
        //进场动画
        getWindow().setEnterTransition(slide);
        //退场动画
        getWindow().setExitTransition(slide);

    }
}

151.以指定位置的转场动画切换两个Activity
书上是用到了ActivityOptionsCompat这个类,调用了makeScaleUpAnimation()。
makeScaleUpAnimation(View source, int startX, int startY, int startWidth, int startHeight)
View source - 参照物
int startX - 相对于 source,新 Activity 开始的位置
int startY - 同 startX,只不过这是 Y 轴方向上的
int startWidth - 第二个 Activity 在做放大动画前一开始的初始宽度
int startHeight - 这当然就是初始高度了

使用代码应该就是这个,但是我试过了完全看不出来效果。可能就像这个链接说的,切换速度太快了吧。
Android 动画总结(8) - Activity 转场动画
https://www.jianshu.com/p/7dbd8c16ca6f

 ActivityOptionsCompat compat = ActivityOptionsCompat.makeScaleUpAnimation(view, 0,0, view.getWidth(),  view.getHeight());
ActivityCompat.startActivity(this, new Intent(this, Main2Activity.class), compat.toBundle());

参考链接:
Android Transition(Android过渡动画)
https://www.jianshu.com/p/1007f300f17a
Android 动画总结(8) - Activity 转场动画
https://www.jianshu.com/p/7dbd8c16ca6f
最炫Material Design风过渡动画
https://www.jianshu.com/p/cdf36a191677
ActivityOptionsCompat实现MD风格的Activity过渡动画
https://www.jianshu.com/p/6c42a7157781

152.在切换Activity时叠加缩放动画和转场动画
这里的知识点 是makeSceneTransitionAnimation的叠加使用。
activity_main

<android.support.constraint.ConstraintLayout
    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"
    android:orientation="vertical">


    <ImageView
        android:id="@+id/imageView"
        android:layout_width="94dp"
        android:layout_height="100dp"
        app:srcCompat="@drawable/test"
         app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="205dp"
        android:layout_marginLeft="134dp"
        app:layout_constraintLeft_toLeftOf="parent"
        />
</android.support.constraint.ConstraintLayout>

MainActivity

public class MainActivity extends AppCompatActivity{
    private ImageView mImageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.imageView);
        mImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ActivityOptionsCompat activityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this,
                        view,"");
                startActivity(new Intent(MainActivity.this, Main2Activity.class),activityOptionsCompat.toBundle());
            }
        });
    }

}

activity_main2

<android.support.constraint.ConstraintLayout
    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.cc.uisample.Main2Activity">
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="337dp"
        android:layout_height="439dp"
        android:layout_marginRight="5dp"
        android:layout_marginTop="36dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/test"/>


</android.support.constraint.ConstraintLayout>

Main2Activity

public class Main2Activity extends AppCompatActivity {
    private ImageView mImageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        //进场动画
        getWindow().setEnterTransition(new Explode().setDuration(2000));
        //退场动画
        getWindow().setExitTransition(new Explode().setDuration(2000));
        mImageView = (ImageView) findViewById(R.id.imageView);
        ScaleAnimation scaleAnimation = new ScaleAnimation(0.0f,1.0f,
                0.0f,1.0f, Animation.RELATIVE_TO_SELF,0.5f,
                Animation.RELATIVE_TO_SELF,0.5f);
        scaleAnimation.setDuration(2000);
        mImageView.setAnimation(scaleAnimation);
        scaleAnimation.start();


    }
}

补间动画详解五 缩放动画ScaleAnimation
https://www.jianshu.com/p/6c42a7157781

153.在切换Activity的转场动画中共享多对元素
这里的知识点是共享元素切换动画。
MainActivity

public class MainActivity extends AppCompatActivity{
    private ImageView mImageView1;
    private ImageView mImageView2;
    private Button mButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView1 = (ImageView) findViewById(R.id.imageView1);
        mImageView2 = (ImageView) findViewById(R.id.imageView2);
        mButton = (Button) findViewById(R.id.button);

        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ActivityOptionsCompat activityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this,
                        new Pair<View,String>(mImageView1,"share1"), new Pair<View,String>(mImageView2,"share2"));
                startActivity(new Intent(MainActivity.this, Main2Activity.class),activityOptionsCompat.toBundle());
            }
        });
    }


}

activity_main

<android.support.constraint.ConstraintLayout
    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"
    android:orientation="vertical">


    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="94dp"
        android:layout_height="100dp"
        app:srcCompat="@drawable/test"
         app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="26dp"
        android:layout_marginLeft="71dp"
        app:layout_constraintLeft_toLeftOf="parent"/>
    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="94dp"
        android:layout_height="100dp"
        app:srcCompat="@drawable/flower"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="26dp"
        android:layout_marginRight="89dp"
        app:layout_constraintRight_toRightOf="parent"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        android:layout_marginLeft="133dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="154dp"/>
</android.support.constraint.ConstraintLayout>

Main2Activity

public class Main2Activity extends AppCompatActivity {
    private ImageView mImageView1;
    private ImageView mImageView2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        mImageView1 = (ImageView) findViewById(R.id.imageView1);
        mImageView2 = (ImageView) findViewById(R.id.imageView2);
        ViewCompat.setTransitionName(mImageView1,"share1");
        ViewCompat.setTransitionName(mImageView2,"share2");

    }
}

activity_main2

<android.support.constraint.ConstraintLayout
    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.cc.uisample.Main2Activity">
    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="273dp"
        android:layout_height="223dp"
        android:layout_marginRight="55dp"
        android:layout_marginTop="34dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/test"/>

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="219dp"
        android:layout_height="221dp"
        app:srcCompat="@drawable/flower"
        android:layout_marginLeft="83dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="33dp"/>


</android.support.constraint.ConstraintLayout>

参考链接:
Activity 切换动画---点击哪里从哪放大
https://www.jianshu.com/p/559b5ed973f1

154.使用FragmentTransaction自定义转场动画
书上是调用了setCustomAnimations方法实现的。
可以参考这篇:
Fragment进入退出动画(Fragment转场动画)
https://www.jianshu.com/p/8e131cd8524b

155.使用TransitionManager实现上下滑动动画
这里是用的TransitionManager的beginDelayedTransition()函数。
TransitionManager存在于2个包中,一个是android.support.transition,另一个是android.transition。
这里是android.support.transition。
这里是简略版。
xml

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src = "@drawable/test"/>
</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity{

    private RelativeLayout mRootView;
    private ImageView mImageView;
    private boolean isChanged;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView = (ImageView) findViewById(R.id.imageView);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TransitionManager.beginDelayedTransition(mRootView);
                RelativeLayout.LayoutParams layoutParams =new RelativeLayout.LayoutParams(mImageView.getMeasuredWidth(), mImageView.getMeasuredHeight());
                if (isChanged){
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,RelativeLayout.TRUE);
                }else {
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.TRUE);
                }
                isChanged = !isChanged;
                mImageView.setLayoutParams(layoutParams);
            }
        });

    }

其实在android官方文档的动画分类中,应该只有视图动画和属性动画。
这是Transition的文档。
https://developer.android.google.cn/reference/android/transition/package-summary?hl=en

延伸:
Android 过渡(Transition)动画解析之基础篇
https://www.jianshu.com/p/b72718bade45
Android Transition(Android过渡动画)
https://blog.csdn.net/wuyuxing24/article/details/78857912
android中LayoutParams设置参数的理解

156.使用TransitionManager实现围绕Y轴旋转
这里是android.transition包中的TransitionManager。

public class MainActivity extends AppCompatActivity{

    private RelativeLayout mRootView;
    private ImageView mImageView;
    private boolean isChanged;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView = (ImageView) findViewById(R.id.imageView);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ChangeTransform changeTransform = new ChangeTransform();
                changeTransform.setDuration(2000);
                TransitionManager.beginDelayedTransition(mRootView,changeTransform );
                if (isChanged){
                    mImageView.setRotationY(0f);
                }else {
                    mImageView.setRotationY(45f);
                }
                isChanged = !isChanged;

            }
        });

    }

}

xml

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src = "@drawable/test"/>
</RelativeLayout>

157.使用TransitionManager实现Fade动画效果

<android.support.constraint.ConstraintLayout
       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:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="140dp"
        android:layout_height="300dp"
        android:src = "@mipmap/image1"
        android:layout_marginLeft="49dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="127dp"/>
    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="140dp"
        android:layout_height="300dp"
        android:src = "@mipmap/image2"
        android:layout_marginRight="35dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="126dp"/>
    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="140dp"
        android:layout_height="260dp"
        android:src = "@mipmap/image3"
        android:layout_marginLeft="49dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="127dp"
         />
    <ImageView
        android:id="@+id/imageView4"
        android:layout_width="140dp"
        android:layout_height="260dp"
        android:src = "@mipmap/test"
        android:layout_marginRight="35dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="126dp"
        />
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{

    private ConstraintLayout mRootView;
    private ImageView mImageView1;
    private ImageView mImageView2;
    private ImageView mImageView3;
    private ImageView mImageView4;

    private boolean isChanged;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( ConstraintLayout) findViewById(R.id.root_view);
        mImageView1 = (ImageView) findViewById(R.id.imageView1);
        mImageView2 = (ImageView) findViewById(R.id.imageView2);
        mImageView3 = (ImageView) findViewById(R.id.imageView3);
        mImageView4 = (ImageView) findViewById(R.id.imageView4);

        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TransitionManager.beginDelayedTransition(mRootView,new Fade().setDuration(5000));
                toggleVisible(mImageView1,mImageView2);

            }
        });

    }

    private static void toggleVisible(View... views){
        for (View view:views){
            boolean isVisible = view.getVisibility() == View.VISIBLE;
            view.setVisibility(isVisible?View.INVISIBLE:View.VISIBLE);
        }
    }

}

158.使用TransitionManager组合多个不同动画
效果是点击某一图像,该图像缩放,而其他图像飞出屏幕。

<android.support.constraint.ConstraintLayout
       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:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="90dp"
        android:layout_height="188dp"
        android:src = "@mipmap/image1"
        android:layout_marginLeft="77dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="43dp"
        tools:layout_editor_absoluteY="47dp"
        tools:layout_editor_absoluteX="78dp"/>
    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="102dp"
        android:layout_height="146dp"
        android:src = "@mipmap/image2"
        android:layout_marginRight="88dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="68dp"
        />
    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="88dp"
        android:layout_height="150dp"
        android:src = "@mipmap/image3"
        android:layout_marginLeft="79dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="259dp"
        />
    <ImageView
        android:id="@+id/imageView4"
        android:layout_width="86dp"
        android:layout_height="128dp"
        android:src = "@mipmap/test"
        android:layout_marginRight="88dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="272dp"
        />
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{

    private ConstraintLayout mRootView;
    private ImageView mImageView1;
    private ImageView mImageView2;
    private ImageView mImageView3;
    private ImageView mImageView4;

    private boolean isChanged;
    private int mWidth;
    private int mHeight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( ConstraintLayout) findViewById(R.id.root_view);
        mImageView1 = (ImageView) findViewById(R.id.imageView1);
        mImageView1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                set(view);
            }
        });
        mImageView2 = (ImageView) findViewById(R.id.imageView2);
        mImageView2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                set(view);
            }
        });
        mImageView3 = (ImageView) findViewById(R.id.imageView3);
        mImageView3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                set(view);
            }
        });
        mImageView4 = (ImageView) findViewById(R.id.imageView4);
        mImageView4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                set(view);
            }
        });


    }

    private void set(View view){
        Explode explode = new Explode();
        ChangeBounds changeBounds = new ChangeBounds();
        TransitionSet transitionSet = new TransitionSet();
        transitionSet.addTransition(explode).addTransition(changeBounds);
        transitionSet.setDuration(500);
        TransitionManager.beginDelayedTransition(mRootView,transitionSet);
        changeSize(view);
        changeVisibility(mImageView1,mImageView2,mImageView3,mImageView4);
        view.setVisibility(View.VISIBLE);
    }


    private void changeSize(View view){
        isChanged = !isChanged;
        ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
        if (isChanged){
            mWidth = view.getLayoutParams().width;
            mHeight = view.getLayoutParams().height;
            layoutParams.width = (int) (2.5 * view.getLayoutParams().width);
            layoutParams.height = (int) (2.5 * view.getLayoutParams().height);
        }else {
            layoutParams.width = mWidth;
            layoutParams.height = mHeight;
        }
        view.setLayoutParams(layoutParams);
    }

    private void changeVisibility(View... views){
        for (View view:views){
            boolean isVisible = view.getVisibility() == View.VISIBLE;
            view.setVisibility(isVisible?View.INVISIBLE:View.VISIBLE);
        }
    }

}

159.使用TransitionManager实现单布局过渡动画

<FrameLayout
       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:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="90dp"
        android:layout_height="188dp"
        android:src = "@mipmap/image1"/>
</FrameLayout>
public class MainActivity extends AppCompatActivity{
    private FrameLayout mRootView;
    private ImageView mImageView1;
    private boolean isChanged;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( FrameLayout) findViewById(R.id.root_view);
        mImageView1 = (ImageView) findViewById(R.id.imageView1);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ChangeBounds changeBounds = new ChangeBounds();
                changeBounds.setPathMotion(new ArcMotion());
                changeBounds.setDuration(5000);
                TransitionManager.beginDelayedTransition(mRootView,changeBounds);
                FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mImageView1.getLayoutParams();
                layoutParams.gravity = isChanged?(Gravity.LEFT | Gravity.TOP) : (Gravity.BOTTOM | Gravity.RIGHT);
                mImageView1.setLayoutParams(layoutParams);
                isChanged = !isChanged;
            }
        });
    }

}

延伸:
从LayoutParams说起到代码动态布局
https://www.jianshu.com/p/0d6f753fdd92

160.使用TransitionManager实现平移过渡动画
这里主要是用到了TransitionManager.go()函数。
activity_main

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <include layout="@layout/scene1"/>

</RelativeLayout>

scene1

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src = "@drawable/dog_1"/>

</RelativeLayout>

scene2

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src = "@drawable/test"/>

</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private boolean isChanged;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isChanged){
                    Scene scene = Scene.getSceneForLayout(mRootView,R.layout.scene1,MainActivity.this);
                    Slide slide = new Slide();
                    slide.setDuration(5000);
                    slide.setSlideEdge(Gravity.BOTTOM);
                    Transition transition = slide;
                    TransitionManager.go(scene,transition);
                }else {
                    Scene scene = Scene.getSceneForLayout(mRootView,R.layout.scene2,MainActivity.this);
                    Slide slide = new Slide();
                    slide.setDuration(5000);
                    slide.setSlideEdge(Gravity.BOTTOM);
                    Transition transition = slide;
                    TransitionManager.go(scene,transition);
                }
                isChanged = !isChanged;

            }
        });
    }

}

延伸:
Android动画 —— 过渡框架
https://www.jianshu.com/p/c3de01014a5f
Android动画 —— 布局动画与布局过渡
https://www.jianshu.com/p/8e0e54a4051d

161.使用TransitionManager实现缩放部分图像
这里是调用了setClipBounds函数。
scene1

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src = "@drawable/test"/>

</RelativeLayout>

scene2

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src = "@drawable/test"/>

</RelativeLayout>

activity_main

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <include layout="@layout/scene1"/>

</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //设置过度动画的范围在右下角
                mRootView.setClipBounds(new Rect(mRootView.getWidth() / 2,mRootView.getHeight() / 2,mRootView.getWidth(),mRootView.getHeight()));
                Scene scene = Scene.getSceneForLayout(mRootView,R.layout.scene2,MainActivity.this);
                TransitionManager.go(scene,new ChangeBounds().setDuration(5000));

            }
        });
    }

}

162.使用TransitionManager实现矢量路径动画
书上给的是2种,一种是xml方式写好运动轨迹,另一种是java方式。轨迹部分定义是没有问题的,但是书上这里调用了TransitionManager.go方法去实现运动动画,实际运行我没有成功,后面我改用TransitionManager.beginDelayedTransition方法了。

首先,在目录res下创建transition文件夹,然后新建path_motion.xml文件。
path_motion.xml

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
               android:duration="5000"
               android:interpolator="@android:interpolator/decelerate_cubic">
<changeBounds>
    <patternPathMotion
        android:patternPathData="M200 0 L50 250 L300 250 L200 500"/>
</changeBounds>
</transitionSet>

activity_main

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src = "@drawable/test"/>

</RelativeLayout>

如果使用xml方式,MainActivity如下所示。

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView = (ImageView) findViewById(R.id.image1);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                RelativeLayout.LayoutParams layoutParams =new RelativeLayout.LayoutParams(mImageView.getMeasuredWidth(), mImageView.getMeasuredHeight());
                layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.TRUE);
                mImageView.setLayoutParams(layoutParams);
                TransitionManager.beginDelayedTransition(mRootView, TransitionInflater.from(MainActivity.this).inflateTransition(R.transition.path_motion));

            }
        });
    }

}

如果使用纯java方式,代码如下

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView = (ImageView) findViewById(R.id.image1);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //M200 0 L50 250 L300 250 L200 500
                Path path = new Path();
                path.moveTo(200,0);
                path.lineTo(50,250);
                path.lineTo(300,250);
                path.lineTo(200,500);
                PatternPathMotion patternPathMotion = new PatternPathMotion();
                patternPathMotion.setPatternPath(path);
                ChangeBounds changeBounds = new ChangeBounds();
                changeBounds.setPathMotion(patternPathMotion);
                changeBounds.setDuration(5000);
                RelativeLayout.LayoutParams layoutParams =new RelativeLayout.LayoutParams(mImageView.getMeasuredWidth(), mImageView.getMeasuredHeight());
                layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.TRUE);
                mImageView.setLayoutParams(layoutParams);
                TransitionManager.beginDelayedTransition(mRootView, changeBounds);

            }
        });
    }

}

参考链接:
Android 5.0 过渡动画
https://www.jianshu.com/p/ca03f055607d
Android Transition——基础篇
https://blog.csdn.net/sinat_33585352/article/details/78607493
场景过渡动画(Scene Transition)-简单使用
https://blog.csdn.net/qq_38261174/article/details/79773729
lint 总结(未完成)
https://www.jianshu.com/p/bb712fc4ab1c

163.使用TransitionManager同时实现多种动画
首先,在目录res下创建transition文件夹,然后新建transition_set.xml。
transition_set.xml

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
               android:duration="5000"
               android:interpolator="@android:interpolator/decelerate_cubic">
    <explode/>
    <fade/>
</transitionSet>

activity_main

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src = "@drawable/test"/>

</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView = (ImageView) findViewById(R.id.image1);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TransitionManager.beginDelayedTransition(mRootView, TransitionInflater.from(MainActivity.this).inflateTransition(R.transition.transition_set));
                toggleVisible(mImageView);
            }
        });
    }
    private static void toggleVisible(View... views){
        for (View view:views){
            boolean isVisible = view.getVisibility() == View.VISIBLE;
            view.setVisibility(isVisible?View.INVISIBLE:View.VISIBLE);
        }
    }
}

164.使用TransitionManager实现XML定制动画
这里的知识点是指定id的控件执行动画。
首先,在目录res下创建transition文件夹,然后新建fade_transition.xml文件。

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
              android:duration="5000"
              android:interpolator="@android:interpolator/decelerate_cubic">
  <fade android:fadingMode="fade_in">
      <targets>
          <target android:targetId="@id/image2"/>
      </targets>
  </fade>
   <fade android:fadingMode="fade_out">
       <targets>
           <target android:targetId="@id/image2"/>
       </targets>
   </fade>
</transitionSet>

activity_main

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <include layout="@layout/scene1"/>

</RelativeLayout>

scene1

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src = "@drawable/test"/>

</RelativeLayout>

scene2

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image2"
        android:layout_alignParentBottom="true"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src = "@drawable/test"/>

</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private ImageView mImageView1;
    private ImageView mImageView2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView1 = (ImageView) findViewById(R.id.image1);
        mImageView2 = (ImageView) findViewById(R.id.image2);

        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Scene scene = Scene.getSceneForLayout(mRootView,R.layout.scene2,MainActivity.this);
                TransitionManager.go(scene, TransitionInflater.from(MainActivity.this).inflateTransition(R.transition.fade_transition));

            }
        });
    }

}

165.使用TransitionManager指定控件执行动画
165与164的差异就是一个是xml方式,一个是java方式。
其余部分不变,MainActivity 里面稍微改一点。

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private ImageView mImageView1;
    private ImageView mImageView2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView1 = (ImageView) findViewById(R.id.image1);
        mImageView2 = (ImageView) findViewById(R.id.image2);

        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Scene scene = Scene.getSceneForLayout(mRootView,R.layout.scene2,MainActivity.this);
                Fade fade = new Fade();
                fade.setDuration(5000);
                fade.addTarget(R.id.image2);
                TransitionManager.go(scene, fade);

            }
        });
    }

}

166.使用TransitionManager实现列表项滑入动画
这里的知识点是把RecyclerView当做ViewGroup,使用 TransitionManager.beginDelayedTransition,实现动画效果。

 TransitionSet transitionSet = new TransitionSet();
 Slide slide = new Slide();
 slide.setSlideEdge(Gravity.RIGHT);
 transitionSet.addTransition(slide);
 transitionSet.setDuration(2000);
 TransitionManager.beginDelayedTransition(recyclerView,transitionSet);

167.使用TransitionManager实现弧线路径动画
这里的知识点是弧线路径的定义。这里依旧是是使用TransitionManager.go没有动画效果,可能有什么我疏忽的地方,暂时就先不管了。
首先,res下新建transition文件夹,然后新建path.xml。
path.xml

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
               android:duration="5000"
               android:interpolator="@android:interpolator/decelerate_cubic">
<changeBounds>
    <patternPathMotion
        android:patternPathData="M8,10 a4,6 0 1 ,1 6 6"/>
</changeBounds>
</transitionSet>

书上的给出的代码是

Scene scene = Scene.getSceneForLayout(mRootView,R.layout.scene2,MainActivity.this);
TransitionManager.go(scene,TransitionInflater.from(MainActivity.this).inflateTransition(R.transition.path));

168.使用TransitionManager实现裁剪区域动画
这个我不知道这个可能会应用的场景在哪里。
activity_main

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <include layout="@layout/scene1"/>

</RelativeLayout>

scene1

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src = "@drawable/test"/>

</RelativeLayout>

scene2

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src = "@drawable/test"/>

</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private ImageView mImageView1;
    private ImageView mImageView2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView1 = (ImageView) findViewById(R.id.image1);

        Scene scene1 = new Scene(mRootView, LayoutInflater.from(MainActivity.this).inflate(R.layout.scene1,null));
        mImageView1.setClipBounds(new Rect(0,0,300,400));
        TransitionManager.go(scene1);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                View inflate  = LayoutInflater.from(MainActivity.this).inflate(R.layout.scene2,null);
                Scene scene2 = new Scene(mRootView, inflate);
                mImageView2 = (ImageView) inflate.findViewById(R.id.image2);
                mImageView2.setClipBounds(new Rect(300,400,600,800));
                TransitionManager.go(scene2,new ChangeClipBounds().setDuration(5000));

            }
        });
    }

}

169.通过设置和获取控件的Tag确定动画过渡行为

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:tag="1"
        android:src = "@drawable/test"/>

</RelativeLayout>
public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private ImageView mImageView;
    private TransitionDrawable mTransitionDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView = (ImageView) findViewById(R.id.image);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
              if ( (mImageView.getTag().equals("1"))){
                  mTransitionDrawable = new TransitionDrawable(new Drawable[]{getDrawable(R.drawable.test),getDrawable(R.drawable.flower)});
                  mImageView.setTag("2");
              }else if (  mImageView.getTag().equals("2")) {
                  mTransitionDrawable = new TransitionDrawable(new Drawable[]{getDrawable(R.drawable.flower),getDrawable(R.drawable.test)});
                  mImageView.setTag("1");
              }
              mImageView.setImageDrawable(mTransitionDrawable);
              mTransitionDrawable.startTransition(2000);
            }
        });
    }

}

170.在TransitionSet中指定多个动画的执行顺序
activity_main

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <include layout="@layout/scene1"/>

</RelativeLayout>

scene1

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src = "@drawable/test"/>

</RelativeLayout>

scene2

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src = "@drawable/flower"/>

</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView = (ImageView) findViewById(R.id.image);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Scene scene = Scene.getSceneForLayout(mRootView,R.layout.scene2,MainActivity.this);
                Fade fade_in = new Fade(Fade.IN);
                Fade fade_out = new Fade(Fade.OUT);
                TransitionSet transitionSet = new TransitionSet();
                transitionSet.addTransition(fade_out).addTransition(fade_in);
                transitionSet.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
                transitionSet.setDuration(5000);
                TransitionManager.go(scene, transitionSet);

            }
        });
    }

}

171.使用TransitionDrawable透明切换两幅图像
首先在drawable目录下,创建transition.xml文件。
transition.xml

<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/test"/>
    <item android:drawable="@drawable/flower"/>
</transition>

activity_main

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src = "@drawable/test"/>

</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView = (ImageView) findViewById(R.id.image);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TransitionDrawable transitionDrawable = (TransitionDrawable) ResourcesCompat.getDrawable(getResources(), R.drawable.transition, null);
                mImageView.setImageDrawable(transitionDrawable);
                transitionDrawable.startTransition(5000);

            }
        });
    }

}

172.使用AnimatedVectorDrawable实现转圈动画
可以看这篇。
图片压缩知识梳理(6) - VectorDrawable 及 AnimatedVectorDrawable 使用详解
https://www.jianshu.com/p/31d4cd2fba41

173.创建AnimatedVectorDrawableCompat动画
这个类,好像没有什么人用,所以暂时掌握AnimatedVectorDrawable 的用法应该就够了,略过了。

For API 24 and above, this class is delegating to the framework's AnimatedVectorDrawable. For older API version, this class uses ObjectAnimator and AnimatorSet to animate the properties of a VectorDrawableCompat to create an animated drawable.
AnimatedVectorDrawableCompat are defined in the same XML format as AnimatedVectorDrawable.

参考链接:
AnimatedVectorDrawableCompat
https://developer.android.google.cn/reference/androidx/vectordrawable/graphics/drawable/AnimatedVectorDrawableCompat.html?hl=en

174.使用ViewPropertyAnimator创建多个动画
可以参考这篇:
Android ViewPropertyAnimator:让动画变得简单起来!
https://www.jianshu.com/p/d960e69a7e6a

175.自定义selector实现以动画形式改变阴影大小
res下新建animator文件夹,再新建selector.xml文件。
书上android:propertyName是"translationZ",但是我运行后,没有明显的阴影,所以改成rotationX。而且书上这部分代码有遗漏部分,少了个item标签。

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:duration="@android:integer/config_shortAnimTime"
                            android:propertyName="rotationX"
                            android:valueTo="20dp"
                            android:valueType="floatType"/>
        </set>
    </item>
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:duration="@android:integer/config_shortAnimTime"
                            android:propertyName="rotationX"
                            android:valueTo="0"
                            android:valueType="floatType"/>
        </set>
    </item>
</selector>

activity_main

<RelativeLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/root_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        android:clickable="true"
        android:stateListAnimator="@animator/selector"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src = "@drawable/test"/>

</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity{
    private RelativeLayout mRootView;
    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = ( RelativeLayout) findViewById(R.id.root_view);
        mImageView = (ImageView) findViewById(R.id.image);
    }

}

176.使用ripple标签创建中心波纹扩散动画
可以参考这个链接
5.0以上使用Ripple实现水波纹点击效果
https://www.jianshu.com/p/b04b1ea8fbe4

177.使用GLSurfaceView实现3D地球的自转
可以参考这个链接
Android API开发之OpenGL开发之Android OpenGL之使用GLSurfaceView创建一个3D旋转的图形
https://blog.csdn.net/weixin_37730482/article/details/72896474

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,601评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,367评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,249评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,539评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,967评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,929评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,098评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,825评论 0 207
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,609评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,796评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,282评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,603评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,277评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,159评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,959评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,079评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,874评论 2 277

推荐阅读更多精彩内容