Android 场景Scene的使用

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)

相关推荐
Eastsea.Chen19 分钟前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年8 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿10 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神11 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
兰琛11 小时前
20241121 android中树结构列表(使用recyclerView实现)
android·gitee
Y多了个想法12 小时前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526
NotesChapter13 小时前
Android吸顶效果,并有着ViewPager左右切换
android
_祝你今天愉快14 小时前
分析android :The binary version of its metadata is 1.8.0, expected version is 1.5.
android
暮志未晚Webgl15 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5
麦田里的守望者江15 小时前
KMP 中的 expect 和 actual 声明
android·ios·kotlin