Android动画之使用Scenes和Transitions

本文详细介绍如何使用自定义Transition实现复杂的视图变化动画效果。通过创建不同的Scene并利用自定义Transition来控制视图从一个状态过渡到另一个状态,文章提供了详细的步骤说明及代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当看官方文档时,一个脑袋两个大。比较简单的用法,感觉很复杂。
用法到比较简单,分3步走。

1. 创建Scene
定义 Scene对应的布局,这里有两个Scene,对应两个布局item1.xml和item2.xml
item1.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/view1"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:background="@color/colorAccent"
        android:gravity="center"
        android:text="view1"
        android:textColor="#FFF"
        android:textSize="20dp" />

    <TextView
        android:id="@+id/view2"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="view2"
        android:textColor="#FFF"
        android:textSize="20dp" />

</RelativeLayout>

item2.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/view2"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="view2"
        android:textColor="#FFF"
        android:textSize="20dp" />

    <TextView
        android:id="@+id/view1"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:background="@color/colorAccent"
        android:gravity="center"
        android:text="view1"
        android:textColor="#FFF"
        android:textSize="20dp" />
</RelativeLayout>

注意:item1是动画的开始状态,item2是动画的结束状态,其中控件的ID需要一致

在activity的布局中定义一个帧布局FrameLayout作为Scene的rootView。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/rootview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1">

        <include layout="@layout/item1" />
    </FrameLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_margin="20dp"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮" />
    </LinearLayout>
</LinearLayout>

在Activity中创建Scene:

public class MainActivity extends AppCompatActivity{
    //注意当声明帧布局FrameLayout时用的是ViewGroup 
    private ViewGroup rootView;
    private Scene startScene;
    private Scene endScene;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //root布局(很重要)
        rootView = (ViewGroup) findViewById(R.id.rootview);
        //创建场景
        startScene = Scene.getSceneForLayout(rootView, R.layout.item1, this);
        endScene = Scene.getSceneForLayout(rootView, R.layout.item2, this);
    }
}

这样就创建好了Scene。

2.实例化Transition
实例化Transition比较简单就是声明Transition,并new一下就可以了

private Transition transition;

、、、

public void onClick(View view) {
    transition = new ChangeBounds();
}
、、、

如果这么简单就不拿出来单独讲了,这只是用的系统的Transition 就比较简单了。我们这里主要讲的是自定义的Transition,学习这里要学会属性动画。
我们先看一下源码:

public abstract class Transition implements Cloneable {
    //看字面意思就是保存初始Scene的值
    public abstract void captureStartValues(TransitionValues transitionValues);
    //保存结束Scene的值
    public abstract void captureEndValues(TransitionValues transitionValues);

    /**
     ** @param sceneRoot 转换层次结构的根。
     * @param startValues 初始Scene的目标值
     * @param endValues 结束Scene的目标值
     * 这个方法里根据初始值和结束值通过属性动画来设置动画
     */
    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,TransitionValues endValues) {
        return null;
    }
}

这是我自定义的Transition,还有点小问题,当没结束再次进行动画时,容易出屏幕。

DefineTransition.java

@TargetApi(Build.VERSION_CODES.KITKAT)
public class DefineTransition extends Transition {
    private final static String TOP = "TOP";
    private final static String BOTTOM = "BOTTOM";
    private final static String LEFT = "LEFT";
    private final static String RIGHT = "RIGHT";

    //记录开始的状态
    @Override
    public void captureStartValues(TransitionValues transitionValues) {
        View view = transitionValues.view;
        Rect rect = new Rect();
        view.getHitRect(rect);

        //把初始值存储起来
        transitionValues.values.put(TOP, rect.top);
        transitionValues.values.put(BOTTOM, rect.bottom);
        transitionValues.values.put(LEFT, rect.left);
        transitionValues.values.put(RIGHT, rect.right);
    }

    @Override
    public void captureEndValues(TransitionValues transitionValues) {
        View view = transitionValues.view;
        Rect rect = new Rect();
        view.getHitRect(rect);

        //把结束时的值存起来
        transitionValues.values.put(TOP, rect.top);
        transitionValues.values.put(BOTTOM, rect.bottom);
        transitionValues.values.put(LEFT, rect.left);
        transitionValues.values.put(RIGHT, rect.right);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
        if (startValues == null || endValues == null) {
            return null;
        }

        final View endView = endValues.view;
        final View startView = startValues.view;
        //获取初始值
        int startTop = (int) startValues.values.get(TOP);
        int startBottom = (int) startValues.values.get(BOTTOM);
        int startRight = (int) startValues.values.get(RIGHT);
        int startLeft = (int) startValues.values.get(LEFT);
        //获取结束值
        int endTop = (int) endValues.values.get(TOP);
        int endBottom = (int) endValues.values.get(BOTTOM);
        int endRight = (int) endValues.values.get(RIGHT);
        int endLeft = (int) endValues.values.get(LEFT);

        //使用属性动画对特定的空间进行动画的设置
        if (endView.getId() == R.id.view2) {

            ValueAnimator animator;
            if (startLeft == 0) {
                int a = startLeft;
                startLeft = -endLeft;
                endLeft = a;
            }

            animator = ValueAnimator.ofInt(startLeft, endLeft);
            animator.setDuration(2000);
            endView.setY(startTop);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    int current = (int) valueAnimator.getAnimatedValue();
                    endView.setTranslationX(current);
                }
            });


            ValueAnimator positionAnimator;
            if (startTop < 100) {
                int a = startTop;
                startTop = -endTop;
                endTop = a;
            }
            positionAnimator = ValueAnimator.ofInt(startTop, endTop);
            positionAnimator.setDuration(3000);
            endView.setX(startLeft);
            positionAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    int current = (int) valueAnimator.getAnimatedValue();
                    ViewCompat.setTranslationY(endView, current);
                }
            });

            AnimatorSet set = new AnimatorSet();
            set.play(positionAnimator).after(animator);

            return set;
        }

        if (endView.getId() == R.id.view1) {
            ValueAnimator animator;
            if (startLeft == 0) {
                int a = startLeft;
                startLeft = -endLeft;
                endLeft = a;
            }

            animator = ValueAnimator.ofInt(startLeft, endLeft);
            animator.setDuration(2000);
            endView.setY(startTop);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    int current = (int) valueAnimator.getAnimatedValue();
                    ViewCompat.setTranslationX(endView, current);
                }
            });

            ValueAnimator positionAnimator;
            if (startTop == 0) {
                int a = startTop;
                startTop = -endTop;
                endTop = a;
            }

            positionAnimator = ValueAnimator.ofInt(startTop, endTop);
            positionAnimator.setDuration(3000);
            endView.setX(startLeft);

            positionAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    int current = (int) valueAnimator.getAnimatedValue();
                    ViewCompat.setTranslationY(endView, current);
                }
            });

            //动画集合
            AnimatorSet set = new AnimatorSet();
            set.play(positionAnimator).after(animator);
            return set;
        }
        return null;
    }
}

在activity中

private Transition transition;

、、、

public void onClick(View view) {
    //自定义的的transition
    transition = new DefineTransition();
}
、、、

3.启动
这个就是应用TransitionManager.go();就启动了。

public void onClick(View view) {
    //自定义的的transition
    transition = new DefineTransition();
    TransitionManager.go(endScene, transition);
}

注意:在代买中定义的startScene和endScene在代码中只能作为结束时的Scene。而初始的Scene,系统已经自动获取,就是当前你在屏幕中看到的界面,系统已自动捕获。

源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值