FragmentVisible

1. 自测 场景

简易场景 {      // 只考虑最后一个 Fragment

    case1:  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 + add
    add(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 + add
    add(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 = 7
    viewpager.offscreenPageLimit = 1
    {
        初始化 index = 0 { text0
            text0:  onCreate() -> onActivityCreated() -> onResume()
            text1:  onCreate() -> onActivityCreated() -> onResume()
        }

        右滑 第 1 次 { text1
            text0:  setUserVisibleHint(false)
            text1:  setUserVisibleHint(true)
            text2:  onCreate() -> onActivityCreated() -> onResume()
        }

        息屏 {    text1
            text0:  onPause()
            text1:  onPause()
            text2:  onPause()
        }

        亮屏 {    text1
            text0:  onResume()
            text1:  onResume()
            text2:  onResume()
        }

        右滑 第 2 次 { text2
            text0:  onPause()
            text1:  setUserVisibleHint(false)
            text2:  setUserVisibleHint(true)
            text3:  onCreate() -> onActivityCreated() -> onResume()
        }
    }

    viewpager.count = 7
    viewpager.offscreenPageLimit = 2
    {
        初始化 index = 0 { text0
            text0:  onCreate() -> onActivityCreated() -> onResume()
            text1:  onCreate() -> onActivityCreated() -> onResume()
            text2:  onCreate() -> onActivityCreated() -> onResume()
        }
        右滑 第 1 次 { text1
            text0:  setUserVisibleHint(false)
            text1:  setUserVisibleHint(true)
            text3:  onCreate() -> onActivityCreated() -> onResume()
        }
        右滑 第 2 次 { text2
            text1:  setUserVisibleHint(false)
            text2:  setUserVisibleHint(true)
            text4:  onCreate() -> onActivityCreated() -> onResume()
        }
    }
}

2.1.4 简易场景 case4

case4:  Activity + ViewPager2 + Fragment {
    viewpager2.count = 7
    viewpager2.offscreenPageLimit = 1
    {
        初始化 index = 0 { text0
            text0:  onCreate() -> onActivityCreated() -> onResume()
            text1:  onCreate() -> onActivityCreated()
        }

        右滑 第 1 次 { text1
            text0:  onPause()
            text1:  onResume()
            text2:  onCreate() -> onActivityCreated()
        }

        息屏 {    text1
            text1:  onPause()
        }

        亮屏 {    text1
            text1:  onResume()
        }

        右滑 第 2 次 { text2
            text1:  onPause()
            text2:  onResume()
            text3:  onCreate() -> onActivityCreated()
        }

        左滑 第 1 次 { text1
            text2:  onPause()
            text1:  onResume()
        }
    }

    viewpager2.count = 7
    viewpager2.offscreenPageLimit = 2
    {
        初始化 index = 0 { text0
            text0:  onCreate() -> onActivityCreated() -> onResume()
            text1:  onCreate() -> onActivityCreated()
            text2:  onCreate() -> onActivityCreated()
        }

        右滑 第 1 次 { text1
            text0:  onPause()
            text1:  onResume()
            text3:  onCreate() -> onActivityCreated()
        }

        右滑 第 2 次 { text2
            text1:  onPause()
            text2:  onResume()
            text4:  onCreate() -> onActivityCreated()
        }

        左滑 第 1 次 { text1
            text1:  onResume()
            text2:  onPause()
        }
    }
}

2.2.1 复杂场景 case1

考虑到场景复杂,父容器 和 子容器,只做1个通知即可。代码如下:

/**
 * 作为父Fragment, visible 变化后,通知child
 */
fun dispatch2Child(fragment: Fragment, visible: Boolean) {
    val childFragments = fragment.childFragmentManager.fragments
    // 没有 child
    if (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(): Int

    override 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   // 宿主Fragment
    private var visibleListener: OnVisibleListener? = null

    fun setOnVisibleListener(listener: OnVisibleListener) {
        this.visibleListener = listener
    }

    fun setFunctionJob(functionJob: OnVisibleLifecycleJob?) {
        print("setFunctionJob: ${functionJob?.javaClass?.simpleName}")
        this.functionJob = functionJob
    }

    fun onCreate(fragment: Fragment) {
        this.hostFragment = fragment

        logJob = 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 = false
    private var nowVisible = false

    /**
     * className: ==FragmentA
     */
    fun setLogTag(className: String? = "") {
        this.logHeader = "xxq==$className"  // 案例: "xxq====FragmentA"
    }

    /**
     * 修改可见性
     */
    fun updateVisible(visible: Boolean) {
        val fragment = hostFragment ?: return

        if (nowVisible == visible) {
            return
        }
        nowVisible = visible

        // 当前Fragment 可见性修改
        if (visible) {
            callVisible()
        } else {
            callInvisible()
        }

        // 可见性 变化后,分发给 child
        dispatch2Child(fragment, visible)
    }

    /**
     * 可见
     */
    private fun callVisible() {
        if (!hasFirstVisible) {
            hasFirstVisible = true
            visibleListener?.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 加载 Fragment
        const val CASE_CONTAINER_VIEWPAGER = 1  // viewpager 加载 Fragment
        const val CASE_CONTAINER_VIEWPAGER2 = 2 // viewpager2 加载 Fragment

    /**
     * 作为父Fragment, visible 变化后,通知child
     */
    fun dispatch2Child(fragment: Fragment, visible: Boolean) {
        val childFragments = fragment.childFragmentManager.fragments
        // 没有 child
        if (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) {   // 寻找几层,没有,默认 Layout
                return 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? = null

    override 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)
    }
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值