Android转场动画

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yz_cfm/article/details/84995008

Android转场动画

课程目标:

1. 掌握定义转场动画的方法

学习内容:

1. 转场动画的作用

2. 哪些时机需要转场动画

3. 转动画的方法

一、 转场动画的作用

1. 转场动画可以提供视觉连续性。

二、 哪些时机需要转场动画

1. 视觉状态改变时。

   a. 单个视图变化时

   b. 布局变化时

   c. activity跳转时

扫描二维码关注公众号,回复: 4726273 查看本文章

三、 转场动画的方法

1. 揭露效果(单个视图的转场动画)

a. View状态改变时(下面用一个demo演示当一个View在可见和不可见时产生揭露效果)

实践:

xml布局文件: activity_reveal.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/activity_view"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context="com.imooc.transitionanimation.reveal.RevealActivity">



    <CheckBox

        android:text="Play animation"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:id="@+id/checkBox" />



    <View

        android:id="@+id/view"

        android:layout_centerInParent="true"

        android:background="@color/colorAccent"

        android:onClick="onClick"

        android:visibility="invisible"

        android:layout_width="300dp"

        android:layout_height="300dp"/>



    <Button

        android:onClick="onClick"

        android:id="@+id/buttonChangeVisibility"

        android:layout_width="wrap_content"

        android:text="switch"

        android:layout_alignParentBottom="true"

        android:layout_alignParentEnd="true"

        style="?android:buttonBarButtonStyle"

        android:layout_height="wrap_content" />



</RelativeLayout>

java代码: RecealActivity.java

public class RevealActivity extends AppCompatActivity {



    private static final String TAG = "RevealActivity";



    private View mView;

    private CheckBox mPlayAnimationCheckBox;



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_reveal);

        mView = findViewById(R.id.view);

        mPlayAnimationCheckBox = (CheckBox) findViewById(R.id.checkBox);

    }



    public void onClick(View view) {

        final boolean playAnimation = mPlayAnimationCheckBox.isChecked();

        switch (view.getId()) {

            case R.id.buttonChangeVisibility:

                handleChangeVisibility(playAnimation);

                break;

        }

    }



    private void handleChangeVisibility(boolean playAnimation) {

        Log.d(TAG, "handleChangeVisibility() called with: playAnimation = [" + playAnimation + "]");

        Log.d(TAG, "handleChangeVisibility: " + mView.isShown());

        if (playAnimation) {

                      // 有揭露效果时View的变化效果

            if (mView.isShown()) {

                revealExit();

            } else {

                revealEnter();

            }

        } else {

           // 没有揭露效果时View的变化效果

           if (mView.isShown()) {

               mView.setVisibility(View.INVISIBLE);

           } else {

               mView.setVisibility(View.VISIBLE);

           }

        }

    }



    // 通过揭露效果显示View

    private void revealEnter() {

        int w = mView.getWidth();

        int h = mView.getHeight();



        int cx = w;

        int cy = h;



        int r = (int) Math.hypot(w, h);

        // 1. 创建Animator 对象(mView: 显示揭露效果的对象  cx,cy: 产生接口效果的圆心(也就是起始点)  0: 动画开始前半径为0  r: 动画结束的半径)

        Animator animator = ViewAnimationUtils.createCircularReveal(mView, cx, cy, 0, r);



        mView.setVisibility(View.VISIBLE);



        animator.start();

    }



       // 通过揭露效果隐藏View

    private void revealExit() {

        int w = mView.getWidth();

        int h = mView.getHeight();



        int cx = w;

        int cy = h;



        int r = (int) Math.hypot(w, h);

        // 1. 创建Animator 对象(mView: 显示揭露效果的对象  cx,cy: 产生接口效果的圆心(也就是起始点)  r: 动画开始前半径为0  0: 动画结束的半径)

        Animator animator = ViewAnimationUtils.createCircularReveal(mView, cx, cy, r, 0);



        animator.setDuration(5000);



        // 给Animator对象注册监听器,让其在动画结束时,View不可见

        animator.addListener(new AnimatorListenerAdapter() {

            @Override

            public void onAnimationEnd(Animator animation) {

                super.onAnimationEnd(animation);

                mView.setVisibility(View.INVISIBLE);

            }

        });



        animator.start();

    }



}

2.多视图的转场动画

为了完成多视图的转场动画,Android中为我们提供了android.transition包。在这个包下

主要提供三个类:

1. Scene

2. Transition

3. TransitionManager

上面这三个类之间的关系: Scene就是场景,Transition就是转换类型,TransitionManager负责场景的转换,并将不同的转换类型结合到场景转换的过程中。

下面分别来看下这三个类:

1. Scene(场景)

我们屏幕上显示的实际上就是一个View树结构,我们看到的视图其实就是这个View树结构中所有View所处于的某种状态的瞬间,这就是一个场景(Scene)。也就是说我们可以把视图的某一个状态称为一个场景。

获取这个场景的scene对象(从布局中加载一个场景):

scene.getSceneForLayout(sceneRoot, R.layout.scene_overview, this);

参数含义:

sceneRoot:转场发生的地方

R.layout.scene_overview:组成这一场景的布局资源

this:上下文

2. Transition(转换类型)

Android中为我们预定好了一些转换效果,比如:

Fade(淡入淡出):也就是透明度变化

ChangeBounds(改变边界)

AutoTransition(默认自动使用这个效果)

获取Transition对象:

TransitionInflater.from(getBaseContext()).inflateTransition(R.transition.transition);

transition和我们之前的视图对象中Animation以及属性动画中的Animator类似,他们都可以通过xml文件和java代码定义,推荐使用xml文件。

3. TransitionManager

有了场景对象和转换类型,接着就可以进行转场动画了:

TransitionManager.go(mTargetScene, transition);

参数含义:

mTargetScene: 我们要跳转的目标场景

transition:   使用的转换类型,可以使我们自定义的,也可以用Android中提供的,如果不设置这个参数,默认使用AutoTransition这个场景。

实践:

1.使用xml文件自定义一个Transition对象,在res目录下创建一个目录/res/transition/, 然后创建一个xml文件。(/res/transition/transition.xml):

<?xml version="1.0" encoding="utf-8"?>

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">

    <changeImageTransform android:duration="3000">

        <targets android:targetId="@id/image" />

    </changeImageTransform>



    <fade android:duration="3000" android:startDelay="1000">

    </fade>

</transitionSet>

activity布局文件( activity_scene.xml ):

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/activity_scene"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context="com.imooc.transitionanimation.scene.SceneActivity">



    <FrameLayout

        android:id="@+id/scene_root"

        android:layout_width="match_parent"

        android:layout_height="match_parent" />



</RelativeLayout>

进入场景xml布局文件( scene_overview.xml ):

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/activity_scene"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical"

    tools:context="com.imooc.transitionanimation.scene.SceneActivity">



    <ImageView

        android:layout_width="match_parent"

        android:id="@+id/image"

        android:layout_height="0dp"

        android:layout_weight="1"

        android:src="@drawable/chang_bai"

        android:transitionName="@string/pic"

        />



    <RelativeLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginTop="16dp">



        <ImageButton

            android:id="@+id/btnInfo"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_alignParentEnd="true"

            android:layout_marginTop="4dp"

            android:background="?android:selectableItemBackground"

            android:onClick="onClick"

            android:src="@drawable/ic_info_black_24dp" />



        <TextView

            android:id="@+id/tvTitle"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:layout_toStartOf="@id/btnInfo"

            android:text="@string/title"

            android:textAppearance="@style/TextAppearance.AppCompat.Headline" />



        <TextView

            android:id="@+id/tvAddress"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_below="@id/tvTitle"

            android:layout_marginTop="8dp"

            android:text="@string/address"

            android:textAppearance="@style/TextAppearance.AppCompat.Medium" />



    </RelativeLayout>



</LinearLayout>

退出场景xml布局文件( scene_info.xml ):

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/activity_scene"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical"

    tools:context="com.imooc.transitionanimation.scene.SceneActivity">



    <ImageView

        android:id="@+id/image"

        android:layout_width="160dp"

        android:layout_height="120dp"

        android:src="@drawable/chang_bai" />



    <RelativeLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginTop="16dp">



        <ImageButton

            android:id="@+id/btnClose"

            android:transitionName="@string/icon"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_alignParentEnd="true"

            android:layout_marginTop="4dp"

            android:background="?android:selectableItemBackground"

            android:onClick="onClick"

            android:src="@drawable/ic_close_black_24dp" />



        <TextView

            android:id="@+id/tvTitle"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:layout_toStartOf="@id/btnClose"

            android:text="@string/title"

            android:textAppearance="@style/TextAppearance.AppCompat.Title" />



        <TextView

            android:id="@+id/tvAddress"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_below="@id/tvTitle"

            android:layout_marginTop="8dp"

            android:text="@string/address"

            android:textAppearance="@style/TextAppearance.AppCompat.Medium" />



        <TextView

            android:id="@+id/tvInfo"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:layout_below="@id/tvAddress"

            android:layout_marginTop="8dp"

            android:text="@string/info" />



    </RelativeLayout>



</LinearLayout>

2.java代码:

public class SceneActivity extends AppCompatActivity {

    private Scene mOverViewScene;

    private Scene mInfoScene;



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_scene);



        ViewGroup sceneRoot = (ViewGroup) findViewById(R.id.scene_root);

        // 获取进入时的场景对象

        mOverViewScene = Scene.getSceneForLayout(sceneRoot, R.layout.scene_overview, getBaseContext());

               //  获取退出时的场景对象

        mInfoScene = Scene.getSceneForLayout(sceneRoot, R.layout.scene_info, getBaseContext());



        // 第一次加载布局时使用的场景转换,如果没有Transition参数,默认使用AutoTransition转换类型

        TransitionManager.go(mOverViewScene);

    }



    public void onClick(View view) {

        switch (view.getId()) {

            case R.id.btnInfo:

                // 自定义场景转换类型transition

                Transition transition = TransitionInflater.from(getBaseContext())

                        .inflateTransition(R.transition.transition);

                TransitionManager.go(mInfoScene, transition);

                break;

            case R.id.btnClose:

                TransitionManager.go(mOverViewScene);

                break;

        }

    }



}

3.Activity间转场动画:

ActivityA和ActivityB之间跳转的动画涉及到3次动画:

ActivityA跳转到ActivityB时,ActivityA就会有离场动画(Exit),进入到ActivityB时ActivityB就有进场动画(Enter),当ActivityB按Back键返回到ActivityA时,ActivityA就又被再次进入,此时又是一种动画效果(Re_enter)。

使用转场动画: (ActivityOptions)

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this);

startActivity(intent, options.toBundle());

转场动画的动画类型: (Transition)

Android系统中默认的有三种:

1. Fade(淡入淡出)

2. Slide(滑动效果)

3. Explode(爆炸效果)

实践:

a. xml布局文件:

activity_first.xml:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/activity_first"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context="com.imooc.transitionanimation.activity.FirstActivity">



    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content">



        <ImageView

            android:id="@+id/iv1"

            android:layout_width="0dp"

            android:layout_height="160dp"

            android:layout_weight="1"

            android:background="?attr/selectableItemBackground"

            android:onClick="onClick"

            android:src="@drawable/pic1" />



        <ImageView

            android:id="@+id/iv2"

            android:layout_width="0dp"

            android:layout_height="160dp"

            android:layout_weight="1"

            android:background="?attr/selectableItemBackground"

            android:onClick="onClick"

            android:src="@drawable/pic2" />

    </LinearLayout>



    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content">



        <ImageView

            android:id="@+id/iv3"

            android:layout_width="0dp"

            android:layout_height="160dp"

            android:layout_weight="1"

            android:background="?attr/selectableItemBackground"

            android:onClick="onClick"

            android:src="@drawable/pic3" />



        <ImageView

            android:id="@+id/iv4"

            android:layout_width="0dp"

            android:layout_height="160dp"

            android:layout_weight="1"

            android:background="?attr/selectableItemBackground"

            android:onClick="onClick"

            android:src="@drawable/pic4" />



    </LinearLayout>



</LinearLayout>

activity_second.xml:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/activity_second"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context="com.imooc.transitionanimation.activity.SecondActivity">



    <ImageView

        android:id="@+id/iv"

        <!-- 共享元素定义的名称,要和java代码中相同 -->

        android:transitionName="img"

        android:layout_centerInParent="true"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content" />



</RelativeLayout>

b. java代码:

FirstActivity.java:

public class FirstActivity extends Activity {



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_first);

    }



    public void onClick(View view) {

        int resId = -1;

        switch (view.getId()) {

            case R.id.iv1:

                resId = R.drawable.pic1;

                break;

            case R.id.iv2:

                resId = R.drawable.pic2;

                break;

            case R.id.iv3:

                resId = R.drawable.pic3;

                break;

            case R.id.iv4:

                resId = R.drawable.pic4;

                break;

        }

        Intent intent = new Intent(this, SecondActivity.class);

        intent.putExtra("resId", resId);

        // 定义动画的类型(爆炸效果)

        Transition transition = new Explode();

        // 去除不想实现动画效果的view(这里设置的是状态栏不参加动画效果)

        transition.excludeTarget(android.R.id.statusBarBackground, true);

        

        // 设置进场动画

        getWindow().setEnterTransition(transition);

        // 设置离场动画

        getWindow().setExitTransition(transition);

        // 设置再次进入时的动画

        getWindow().setReenterTransition(transition);

        // 为共享元素设置特定的动画效果

        getWindow().setSharedElementEnterTransition(transition);



        // 定义共享元素(注意这里的名称"img"要和xml布局文件中的view transitionName属性名称一样)

        Pair<View, String> shareElement = Pair.create(view, "img");

        // 创建实现转场动画需要的options对象

        ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, shareElement);

        startActivity(intent, options.toBundle());

    }

}

SecondActivity.java:

public class SecondActivity extends Activity {



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_second);

        int resId = getIntent().getExtras().getInt("resId");

        ImageView iv = (ImageView) findViewById(R.id.iv);

        iv.setTransitionName("img");

        iv.setImageResource(resId);

        

        // 下面这些含义解释如上

        Transition transition = new Explode();

        transition.excludeTarget(android.R.id.statusBarBackground, true);

        getWindow().setEnterTransition(transition);

        getWindow().setExitTransition(transition);

    }

}

猜你喜欢

转载自blog.csdn.net/yz_cfm/article/details/84995008