FragmentVisible
2024-05-14 12:24:35
1. 自测 场景
简易场景 { // 只考虑最后一个 Fragmentcase1: Activity + Fragment case2: Activity + FragmentA + FragmentB 「只考虑 FragmentB 自身的变化」case3: Activity + ViewPager + Fragment case4: Activity + ViewPager2 + Fragment
}复杂场景 { case1: Activity + FragmentA + FragmentB// FragmentA 可见性 变化,对 FragmentB 的影响
}
2. 自测 场景结果
2.1.1 简易场景 case1
case1: Activity + Fragment {replace = remove + addadd(int, fragment) onCreate() -> onActivityCreated() -> onResume()remove(fragment) onPause() -> onDestroy()hide(fragment) onHiddenChanged(true)show(fragment) onHiddenChanged(false)息屏(fragmentA) onPause()亮屏(fragmentA) onResume() }
2.1.2 简易场景 case2
case2: Activity + FragmentA + FragmentB 「只考虑 FragmentB 自身的变化」{replace = remove + addadd(int, fragment) onCreate() -> onActivityCreated() -> onResume()remove(fragment) onPause() -> onDestroy()hide(fragment) onHiddenChanged(true)show(fragment) onHiddenChanged(false)息屏(fragmentA) onPause()亮屏(fragmentA) onResume() }
2.1.3 简易场景 case3
case3: Activity + ViewPager + Fragment {viewpager.count = 7viewpager.offscreenPageLimit = 1{初始化 index = 0 { text0text0: onCreate() -> onActivityCreated() -> onResume()text1: onCreate() -> onActivityCreated() -> onResume()}右滑 第 1 次 { text1text0: setUserVisibleHint(false)text1: setUserVisibleHint(true)text2: onCreate() -> onActivityCreated() -> onResume()}息屏 { text1text0: onPause()text1: onPause()text2: onPause()}亮屏 { text1text0: onResume()text1: onResume()text2: onResume()}右滑 第 2 次 { text2text0: onPause()text1: setUserVisibleHint(false)text2: setUserVisibleHint(true)text3: onCreate() -> onActivityCreated() -> onResume()}}viewpager.count = 7viewpager.offscreenPageLimit = 2{初始化 index = 0 { text0text0: onCreate() -> onActivityCreated() -> onResume()text1: onCreate() -> onActivityCreated() -> onResume()text2: onCreate() -> onActivityCreated() -> onResume()}右滑 第 1 次 { text1text0: setUserVisibleHint(false)text1: setUserVisibleHint(true)text3: onCreate() -> onActivityCreated() -> onResume()}右滑 第 2 次 { text2text1: setUserVisibleHint(false)text2: setUserVisibleHint(true)text4: onCreate() -> onActivityCreated() -> onResume()}} }
2.1.4 简易场景 case4
case4: Activity + ViewPager2 + Fragment {viewpager2.count = 7viewpager2.offscreenPageLimit = 1{初始化 index = 0 { text0text0: onCreate() -> onActivityCreated() -> onResume()text1: onCreate() -> onActivityCreated()}右滑 第 1 次 { text1text0: onPause()text1: onResume()text2: onCreate() -> onActivityCreated()}息屏 { text1text1: onPause()}亮屏 { text1text1: onResume()}右滑 第 2 次 { text2text1: onPause()text2: onResume()text3: onCreate() -> onActivityCreated()}左滑 第 1 次 { text1text2: onPause()text1: onResume()}}viewpager2.count = 7viewpager2.offscreenPageLimit = 2{初始化 index = 0 { text0text0: onCreate() -> onActivityCreated() -> onResume()text1: onCreate() -> onActivityCreated()text2: onCreate() -> onActivityCreated()}右滑 第 1 次 { text1text0: onPause()text1: onResume()text3: onCreate() -> onActivityCreated()}右滑 第 2 次 { text2text1: onPause()text2: onResume()text4: onCreate() -> onActivityCreated()}左滑 第 1 次 { text1text1: onResume()text2: onPause()}} }
2.2.1 复杂场景 case1
考虑到场景复杂,父容器 和 子容器,只做1个通知即可。代码如下:
/*** 作为父Fragment, visible 变化后,通知child*/
fun dispatch2Child(fragment: Fragment, visible: Boolean) {val childFragments = fragment.childFragmentManager.fragments// 没有 childif (childFragments.isEmpty()) {return}// 当前Fragment可见性修改,通知下去childFragments.forEachIndexed { index, child ->if (child.isAdded && child is OnVisibleListener) {child.onParentFragmentVisibleChanged(visible)}}
}class ChildFragment: Fragment(), OnVisibleListener {override fun onParentFragmentVisibleChanged(parentVisible: Boolean) {// TODO 给一个默认 逻辑;可被复写}
}
3. 代码实现
1. BaseFragment // 基类
2. VisibleJobImpl // 对接 BaseFragment,和 具体功能的实现类
3. VisibleLogJob // 提供 BaseFragment 生命周期的日志功能
4. VFunctionVP2Job、VFunctionLayoutJob、VFunctionVPJob // 适配 ViewPager、ViewPager2 等场景
abstract class BaseFragment : Fragment(), OnVisibleListener {var logTag: String? = ""private var visibleJob = VisibleJobImpl()protected abstract fun getLayoutId(): Intoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)visibleJob.setLogTag(logTag)visibleJob.setOnVisibleListener(this)visibleJob.onCreate(this)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)val customJob = onCreateFunctionJob()if (null != customJob) {visibleJob.setFunctionJob(customJob)} else {// 自动查找 场景val functionJob = when (VisibleJobImpl.findParentContainerCase(view.parent, 3)) {VisibleJobImpl.CASE_CONTAINER_LAYOUT -> VFunctionLayoutJob()VisibleJobImpl.CASE_CONTAINER_VIEWPAGER -> VFunctionVPJob()VisibleJobImpl.CASE_CONTAINER_VIEWPAGER2 -> VFunctionVP2Job()else -> null}visibleJob.setFunctionJob(functionJob)}}override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(getLayoutId(), container, false)}override fun onActivityCreated(savedInstanceState: Bundle?) {super.onActivityCreated(savedInstanceState)visibleJob.onActivityCreated()}override fun onResume() {super.onResume()visibleJob.onResume()}override fun onPause() {visibleJob.onPause()super.onPause()}override fun onDestroy() {visibleJob.onDestroy()super.onDestroy()}override fun setUserVisibleHint(isVisibleToUser: Boolean) {super.setUserVisibleHint(isVisibleToUser)visibleJob.setUserVisibleHint(isVisibleToUser)}override fun onHiddenChanged(hidden: Boolean) {super.onHiddenChanged(hidden)visibleJob.onHiddenChanged(hidden)}open fun onCreateFunctionJob(): OnVisibleLifecycleJob? {return null}fun getVisibleJobImpl(): VisibleJobImpl {return visibleJob}private var nextShouldVisible = false // 父容器改变时,下一次是否需要修改可变性override fun onParentFragmentVisibleChanged(parentVisible: Boolean) {visibleJob.print("onParentFragmentVisibleChanged($parentVisible)")if (parentVisible) { // 父容器,不可见 -> 可见if (nextShouldVisible) {visibleJob.updateVisible(true)}} else { // 父容器,可见 -> 不可见if (isVisible) {visibleJob.updateVisible(false)nextShouldVisible = true}}}open override fun onFragmentFirstVisible() {}open override fun onFragmentVisible() {}open override fun onFragmentInvisible() {}
}
class VisibleJobImpl {private var logJob: VisibleLogJob? = null // 日志实现private var functionJob: OnVisibleLifecycleJob? = null // 功能实现private var hostFragment: Fragment? = null // 宿主Fragmentprivate var visibleListener: OnVisibleListener? = nullfun setOnVisibleListener(listener: OnVisibleListener) {this.visibleListener = listener}fun setFunctionJob(functionJob: OnVisibleLifecycleJob?) {print("setFunctionJob: ${functionJob?.javaClass?.simpleName}")this.functionJob = functionJob}fun onCreate(fragment: Fragment) {this.hostFragment = fragmentlogJob = VisibleLogJob()logJob?.onCreate(fragment, this)functionJob?.onCreate(fragment, this)}fun onActivityCreated() {logJob?.onActivityCreated(this)functionJob?.onActivityCreated(this)}fun onResume() {logJob?.onResume(this)functionJob?.onResume(this)}fun onPause() {logJob?.onPause(this)functionJob?.onPause(this)}fun onDestroy() {logJob?.onDestroy(this)functionJob?.onPause(this)this.hostFragment = null // 清空}fun setUserVisibleHint(isVisibleToUser: Boolean) {logJob?.setUserVisibleHint(this, isVisibleToUser)functionJob?.setUserVisibleHint(this, isVisibleToUser)}fun onHiddenChanged(hidden: Boolean) {logJob?.onHiddenChanged(this, hidden)functionJob?.onHiddenChanged(this, hidden)}private var logHeader = ""private var hasFirstVisible = falseprivate var nowVisible = false/*** className: ==FragmentA*/fun setLogTag(className: String? = "") {this.logHeader = "xxq==$className" // 案例: "xxq====FragmentA"}/*** 修改可见性*/fun updateVisible(visible: Boolean) {val fragment = hostFragment ?: returnif (nowVisible == visible) {return}nowVisible = visible// 当前Fragment 可见性修改if (visible) {callVisible()} else {callInvisible()}// 可见性 变化后,分发给 childdispatch2Child(fragment, visible)}/*** 可见*/private fun callVisible() {if (!hasFirstVisible) {hasFirstVisible = truevisibleListener?.onFragmentFirstVisible()print("onFragmentFirstVisible")}visibleListener?.onFragmentVisible()print("onFragmentVisible")}/*** 不可见*/private fun callInvisible() {visibleListener?.onFragmentInvisible()print("onFragmentInvisible")}/*** 打印日志,adb shell setprop log.tag.xxq V*/fun print(method: String?) {if (Log.isLoggable("xxq", Log.DEBUG)) {Log.d("xxq", "$logHeader.$method")}}companion object {const val CASE_CONTAINER_KEY = "case_container_key"const val CASE_CONTAINER_LAYOUT = 0 // layout 加载 Fragmentconst val CASE_CONTAINER_VIEWPAGER = 1 // viewpager 加载 Fragmentconst val CASE_CONTAINER_VIEWPAGER2 = 2 // viewpager2 加载 Fragment/*** 作为父Fragment, visible 变化后,通知child*/fun dispatch2Child(fragment: Fragment, visible: Boolean) {val childFragments = fragment.childFragmentManager.fragments// 没有 childif (childFragments.isEmpty()) {return}// 当前Fragment可见性修改,通知下去childFragments.forEachIndexed { index, child ->if (child.isAdded && child is OnVisibleListener) {child.onParentFragmentVisibleChanged(visible)}}}/*** 向上查找容器,最多 level 层*/fun findParentContainerCase(view: ViewParent?, level: Int = 3): Int {if (null == view) { // ViewPager2 时,viewParent 为空return CASE_CONTAINER_VIEWPAGER2}if (level <= 0) { // 寻找几层,没有,默认 Layoutreturn CASE_CONTAINER_LAYOUT}if (view is ViewPager) { // ViewPager 校验return CASE_CONTAINER_VIEWPAGER}// 递归查找return findParentContainerCase(view.parent, level - 1)}}
}
class VisibleLogJob : OnVisibleLifecycleJob {override fun onCreate(fragment: Fragment, jobImpl: VisibleJobImpl) {jobImpl.print("onCreate")}override fun onActivityCreated(jobImpl: VisibleJobImpl) {jobImpl.print("onActivityCreated")}override fun onResume(jobImpl: VisibleJobImpl) {jobImpl.print("onResume")}override fun onPause(jobImpl: VisibleJobImpl) {jobImpl.print("onPause")}override fun onDestroy(jobImpl: VisibleJobImpl) {jobImpl.print("onDestroy")}override fun setUserVisibleHint(jobImpl: VisibleJobImpl, isVisibleToUser: Boolean) {jobImpl.print("setUserVisibleHint($isVisibleToUser)")}override fun onHiddenChanged(jobImpl: VisibleJobImpl, hidden: Boolean) {jobImpl.print("onHiddenChanged($hidden)")}
}
class VFunctionVPJob : VFunctionLayoutJob() {private var hostFragment: Fragment? = nulloverride fun onCreate(fragment: Fragment, jobImpl: VisibleJobImpl) {this.hostFragment = fragment}override fun onActivityCreated(jobImpl: VisibleJobImpl) {}override fun onResume(jobImpl: VisibleJobImpl) {if (hostFragment?.userVisibleHint == true) {jobImpl.updateVisible(true)}}override fun onPause(jobImpl: VisibleJobImpl) {if (hostFragment?.userVisibleHint == true) {jobImpl.updateVisible(false)}}override fun onDestroy(jobImpl: VisibleJobImpl) {this.hostFragment = null}override fun setUserVisibleHint(jobImpl: VisibleJobImpl, isVisibleToUser: Boolean) {jobImpl.updateVisible(isVisibleToUser)}override fun onHiddenChanged(jobImpl: VisibleJobImpl, hidden: Boolean) {jobImpl.updateVisible(!hidden)}
}
class VFunctionVP2Job : VFunctionLayoutJob() {override fun onCreate(fragment: Fragment, jobImpl: VisibleJobImpl) {}override fun onActivityCreated(jobImpl: VisibleJobImpl) {}override fun onResume(jobImpl: VisibleJobImpl) {jobImpl.updateVisible(true)}override fun onPause(jobImpl: VisibleJobImpl) {jobImpl.updateVisible(false)}override fun onDestroy(jobImpl: VisibleJobImpl) {}override fun setUserVisibleHint(jobImpl: VisibleJobImpl, isVisibleToUser: Boolean) {}override fun onHiddenChanged(jobImpl: VisibleJobImpl, hidden: Boolean) {jobImpl.updateVisible(!hidden)}
}
open class VFunctionLayoutJob : OnVisibleLifecycleJob {override fun onCreate(fragment: Fragment, jobImpl: VisibleJobImpl) {}override fun onActivityCreated(jobImpl: VisibleJobImpl) {}override fun onResume(jobImpl: VisibleJobImpl) {jobImpl.updateVisible(true)}override fun onPause(jobImpl: VisibleJobImpl) {jobImpl.updateVisible(false)}override fun onDestroy(jobImpl: VisibleJobImpl) {}override fun setUserVisibleHint(jobImpl: VisibleJobImpl, isVisibleToUser: Boolean) {}override fun onHiddenChanged(jobImpl: VisibleJobImpl, hidden: Boolean) {jobImpl.updateVisible(!hidden)}
}
最新文章
- Java基础-集合:set
- 【使用Java编写的B*算法】
- Android系统服务
- IHttpHandler 介绍演示(from 张子阳)
- 搜索引擎原理和简单过程【转】
- Exchange与ADFS单点登录 PART 5:添加ADFS信赖方信任
- 数据结构之图:加权有向图与dijkstra算法找到最短路径,Python——28
- ubuntu14.04中安装opencv2.4.11
- 电脑今天关机,第二天重启 解决方案
- 经典游戏制作教程[zz]
- 伺服电机常用参数设置_伺服驱动器常见参数的设置
- Flash CS3无法导出测试影片问题解决
- OPICS 节假日维护
- 【word毕业论文排版(3)】word导出带有书签的PDF失败,转为用WPS成功
- 最小二乘法以及正交最小二乘(OLS)的推导与简单比较
- python控制步进电机代码tx2_步进电机按键控制.lst
- 用机器学习做风控的氪信,凭什么获金牌投资人章苏阳数千万融资?
- 史上最全的信息收集总结!!!
- Android 监听键盘事件
- cobbler sync 错误