Scene 翻译过来是场景,开发者提供起始布局和结束布局,就可以实现布局之间的过渡动画。
具体可参考 使用过渡为布局变化添加动画效果
大白话,在 Activity 的各个页面之间切换,会带有过渡动画。
打个比方,使用起来类似 Fragment ,单 Activity 多 Fragment 的情景下,为 Fragment 之间的切换添加过渡动画。
Scene 是布局之间的过渡动画,不是 Activity 之间的切换动画。
布局文件创建 Scene
主页面布局,FrameLayout 是 Scene 的父控件,以 include 的方式包含 scene1,也就是默认显示 scene1。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".scene.SceneActivity">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="@+id/button_scene1"
android:text="scene 1"
android:onClick="onSceneButtonClick"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"/>
<Button
android:id="@+id/button_scene2"
android:text="scene 2"
android:onClick="onSceneButtonClick"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"/>
<Button
android:id="@+id/button_scene3"
android:text="scene 3"
android:onClick="onSceneButtonClick"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"/>
<Button
android:id="@+id/button_scene4"
android:text="scene 4"
android:onClick="onSceneButtonClick"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"/>
<Button
android:id="@+id/button_scene5"
android:text="scene 5"
android:onClick="onSceneButtonClick"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"/>
</LinearLayout>
<FrameLayout
android:id="@+id/scene_root"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/linearLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<include layout="@layout/scene1" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
scene1 的布局,很简单,设置颜色和 Button 。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scene_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/purple_200">
<Button
android:text="Scene1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
/>
</RelativeLayout>
其他 Scene 也类似,其他 Scene 的根布局 id 也是 android:id=“@+id/scene_container” ,就颜色和文本不同, 就不贴代码了。
初始化 Scene
通过 findViewById 找到默认的 scene1 ,
其他 Scene 用 getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context)
方法创建,
public class SceneActivity extends AppCompatActivity {
private Scene scene1, scene2 , scene3 , scene4 , scene5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scene);
Objects.requireNonNull(getSupportActionBar()).setTitle(SceneActivity.class.getSimpleName());
ViewGroup mSceneRoot = (ViewGroup) findViewById(R.id.scene_root);
scene1 = new Scene(mSceneRoot, (ViewGroup) mSceneRoot.findViewById(R.id.scene_container));
scene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, SceneActivity.this);
scene3 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene3, SceneActivity.this);
scene4 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene4, SceneActivity.this);
scene5 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene5, SceneActivity.this);
}
}
在 Scene 之间切换
即切换不同的 Scene ,本例 5 个 button ,点击 buttonX 就切换到 SceneX 。
用默认过渡动画切换
切换用 androidx.transition.TransitionManager.go(Scene scene)
方法,切换到目标 Scene 。
这样,在 Scene 之间切换就会自带动画了,比 View.setVisibility(int visibility) 方式更丝滑、好看。
用自定义过渡动画切换
用 androidx.transition.TransitionManager.go(Scene scene, Transition transition)
方法,创建自定义 Transition 。
创建过渡动画 xml
创建 res/transition/ 目录,
选择 transition ,
不得不说 AS 是真的很 6 。
创建 res/transition/transition1.xml 、res/transition/transition2.xml 文件,
transition2.xml 内容
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionOrdering="sequential">
<fade android:fadingMode="fade_out" />
<changeBounds />
<fade android:fadingMode="fade_in" />
</transitionSet>
transition1.xml 里的内容注释掉了,为了方便看有无过度动画的差别。
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<!--<changeBounds />-->
<!--<fade android:fadingMode="fade_in_out"/>-->
</transitionSet>
初始化Transition
初始化 Transition ,
import androidx.transition.Transition;
import androidx.transition.TransitionInflater;
private Transition transition1 , transition2 ;
transition1 = TransitionInflater.from(this).inflateTransition(R.transition.transition1);
transition2 = TransitionInflater.from(this).inflateTransition(R.transition.transition2);
切换
public void onSceneButtonClick(View view){
switch (view.getId()){
case R.id.button_scene1:
TransitionManager.go(scene1); // 切换到 scene1
break;
case R.id.button_scene2:
TransitionManager.go(scene2); // 切换到 scene2
break;
case R.id.button_scene3:
//TransitionManager.go(scene3);
TransitionManager.go(scene3 , transition1); // 切换到 scene3 ,过渡动画用 transition1 ,transition1 为空,实际上无过渡动画
break;
case R.id.button_scene4:
//TransitionManager.go(scene4);
TransitionManager.go(scene4 , transition2); // 切换到 scene4 ,过渡动画用 transition2
break;
case R.id.button_scene5:
//TransitionManager.go(scene5);
//TransitionManager.go(scene5 , null); // 切换到 scene5 , 无过渡动画
break;
default:break;
}
}
监听场景变化
需要在 进入、退出 Scene 时做某些操作,就这样,
scene2.setEnterAction(new Runnable() {
@Override
public void run() {
}
});
scene2.setExitAction(new Runnable() {
@Override
public void run() {
}
});
gif对比
不加过渡动画 TransitionManager.go(sceneX , null)
加过渡动画 TransitionManager.go(sceneX)