Android开发:不替换现有fragment内容如何展示另一fragment并实现淡入淡出
实现方案
1. 调整宿主Activity的布局结构
首先在承载两个Fragment的Activity根布局中,预留两个独立的Fragment容器,互不重叠,从布局层面避免两个Fragment的展示互相影响:
- 左角小窗口容器:固定宽高、位于屏幕左上角,用于承载
fragmentHandle,全程保持可见 - 右角控制容器:固定宽高、位于屏幕右上角,初始设为
View.GONE,用于承载fragmentControl
布局示例:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 页面其他主内容 --> <!-- fragmentHandle容器 左上角画中画区域 --> <FrameLayout android:id="@+id/container_handle" android:layout_width="120dp" android:layout_height="180dp" android:layout_gravity="top|start" android:layout_margin="16dp"/> <!-- fragmentControl容器 右上角控制区域 --> <FrameLayout android:id="@+id/container_control" android:layout_width="200dp" android:layout_height="300dp" android:layout_gravity="top|end" android:layout_margin="16dp" android:visibility="gone"/> </FrameLayout>
2. 一次性初始化Fragment,避免重复创建
在Activity的onCreate生命周期中一次性完成两个Fragment的添加操作,fragmentControl初始直接设为隐藏,全程不会重复创建内部的MotionLayout:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_host) // 配置变更(如屏幕旋转)时避免重复添加Fragment if (savedInstanceState == null) { // 添加全程可见的fragmentHandle supportFragmentManager.beginTransaction() .add(R.id.container_handle, FragmentHandle()) .commit() // 提前添加fragmentControl,初始隐藏 val controlFragment = FragmentControl() supportFragmentManager.beginTransaction() .add(R.id.container_control, controlFragment) .hide(controlFragment) .commit() } }
3. 绑定点击交互与淡入淡出动画
给fragmentHandle设置点击回调,触发时切换fragmentControl的显隐状态,通过Fragment事务自带的自定义动画实现淡入淡出效果,不会影响内部MotionLayout的状态:
// fragmentHandle点击事件触发的回调方法 fun toggleControlPanel() { val controlFragment = supportFragmentManager.findFragmentById(R.id.container_control) ?: return supportFragmentManager.beginTransaction() // 绑定系统自带的淡入淡出动画,也可替换为自定义动画资源 .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out) .apply { if (controlFragment.isHidden) { show(controlFragment) // 如需每次展示时触发MotionLayout的入场动画,可在此处调用 // (controlFragment.binding.motionLayout as MotionLayout).transitionToStart() } else { hide(controlFragment) } } .commit() }
4. MotionLayout状态保持优化
因为fragmentControl只会初始化一次,后续仅做显隐切换,内部MotionLayout的状态会自动保留。如果需要每次展示时重置MotionLayout状态,可在FragmentControl内部重写显隐回调:
override fun onHiddenChanged(hidden: Boolean) { super.onHiddenChanged(hidden) if (!hidden) { // 展示时重置MotionLayout到初始状态,按需添加即可 binding.motionLayout.transitionToStart() } }
注意事项
- 全程不要使用
replace方法操作这两个Fragment,replace会销毁重建旧Fragment,才会导致MotionLayout重复创建的问题 - 如果需要适配系统画中画模式的生命周期,可在
onPictureInPictureModeChanged回调中同步两个Fragment的显隐状态即可
内容的提问来源于stack exchange,提问作者Maria
相关产品推荐
相关产品推荐

