Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StateView的占用高度(宽度)似乎存在BUG #3850

Open
liyuhaolol opened this issue Mar 6, 2024 · 4 comments
Open

StateView的占用高度(宽度)似乎存在BUG #3850

liyuhaolol opened this issue Mar 6, 2024 · 4 comments

Comments

@liyuhaolol
Copy link

liyuhaolol commented Mar 6, 2024

  • 触发这个问题的需求是这样的,很简单。RecyclerView的高度是包裹,而不是撑满布局。

  • 使用的占位View高度同样包裹或者一个不大的高度值。

  • 本来想实现的效果是,无数据的时候,ReclerView底部不会存在大量空白高度。

  • 这时候关键点来了,我发现,当你使用QuickAdapterHelper调用addBeforeAdapter添加Header时,每添加一个BeforeAdapterContentAdapter对应内容区域的高度就会增加一个BeforeAdapter的高度,直到撑满一个父布局。

  • 简单来说就是ContentAdapter对应内容区域会自动变高直到撑满他能撑满的布局高度。造成的问题,1,就算RecyclerView的高度没有达到父布局高度,按照常理RecyclerView应该是无法进行滑动的,但是因为ContentAdapter对应内容区域的高度大于占位View的高度,所以RecyclerView竟然可以滑动。2,就算RecyclerView高度达到了父布局高度,同样因为此时ContentAdapter对应内容区域的高度也变成了父布局的高度,那么RecyclerView下方会滑动出来大量的空白,说白了,这时候ContentAdapter对应内容区域的高度已经不是占位View的高度了,变成了HeaderView总高度+占位View的高度,直到占满父布局,我认为这是个BUG。

  • ContentAdapter对应内容区域的高度应该永远和要显示的占位View高度保持一致不是么???只要不添加HeaderContentAdapter对应内容区域确实可以保证他跟占位View的高度是一致的。但是只要添加了HeaderContentAdapter对应内容区域的高度就会开始变高,这真的不太对吧?

  • 使用的是4.1.4版本,可以用demo比较容易的重现此问题。如需要我可以上传github提供
    WechatIMG15
    WechatIMG16

  • 就如上面2个图简单演示,RecyclerView内容高度本应该是图1的高度,实际也是,但是就像图2,它内部的滑动区域的高度却无端的高了一个Header的高度。这真的就是个BUG吧?

@liyuhaolol
Copy link
Author

  • 更新一些最新发现的情况吧,依然没有找到解决办法,我不理解是我写错了还是不应该这么做。
  • 我通过AS的Layout Inspector查看布局的生成,我发现无论是addBeforeAdapter,还是addAfterAdapter。RecyclerView的高度都会增加对应adapter的高度,这没问题。但是他内部的滑动范围却会成倍增加。也就是增加2个adapter的高度。这是这个问题触发的根本现象。
  • 或者说,contentAdapter对应的高度无论如何都必须跟RecyclerView的高度一致。再加上“Header”和"Footer"就会出现滑动高度是2倍增长的问题。
  • 我认为contentAdapter的对应高度不是应该一直跟他自己的内容实际高度保持一致才对么?为什么会强制跟RecyclerView的高度一致呢?是特性,还是BUG?

@liyuhaolol
Copy link
Author

  • 进一步更新发现的情况,通过看源码基本找到了问题的症结所在,一切都因为StateLayoutVH里将宽高强制写为了MATCH_PARENT。如图所示
    WX20240307-150949@2x
  • 就是因为这个原因,所以承载stateView的空间会强制跟RecyclerView的宽高度保持一致。从而导致了这些现象的发生。
  • 我知道这里不能无脑改成WRAP_CONTENT,所以想讨论是否有好的解决方案,能够兼容RecyclerView的MATCH_PARENTWRAP_CONTENT这两种情况。我也会自己再试试,看能不能找到一个合适的解决方案。

@liyuhaolol
Copy link
Author

  • 我大概找了一个兼容的办法,改起来挺容易得,也好理解,作者您过目一下
  • setStateView方法底下,判断stateView.layoutParams为空的位置添加else分支,判断stateView的宽高设置,动态修改stateLayout的宽高属性,用来兼容RecyclerView占位View的高度是包裹,不撑满空间的情况。
internal class StateLayoutVH(
    parent: ViewGroup,
    stateView: View?,
    private val stateLayout: FrameLayout = FrameLayout(parent.context).apply {
        layoutParams = ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
        )
        setStateView(this, stateView)
    }
) : RecyclerView.ViewHolder(stateLayout), FullSpanAdapterType {


    fun changeStateView(stateView: View?) {
        setStateView(stateLayout, stateView)
    }

    companion object {
        private fun setStateView(rootView: ViewGroup, stateView: View?) {
            if (stateView == null) {
                rootView.removeAllViews()
                return
            }

            if (rootView.childCount == 1) {
                val old = rootView.getChildAt(0)
                if (old == stateView) {
                    // 如果是同一个view,不进行操作
                    return
                }
            }

            stateView.parent.run {
                if (this is ViewGroup) {
                    this.removeView(stateView)
                }
            }

            if (stateView.layoutParams == null) {
                stateView.layoutParams = FrameLayout.LayoutParams(
                    FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT
                ).apply {
                    gravity = Gravity.CENTER
                }
            }else{
                //判断stateView高度,如果不是MATCH_PARENT则把RootView的高度改为WRAP_CONTENT
                if (stateView.layoutParams.height == ViewGroup.LayoutParams.MATCH_PARENT){
                    rootView.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
                }else{
                    rootView.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
                }
                //判断stateView宽度,如果不是MATCH_PARENT则把RootView的高度改为WRAP_CONTENT
                if (stateView.layoutParams.width == ViewGroup.LayoutParams.MATCH_PARENT){
                    rootView.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
                }else{
                    rootView.layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT
                }
            }

            rootView.removeAllViews()
            rootView.addView(stateView)
        }
    }
}

@liyuhaolol
Copy link
Author

#3851 已提交PR,上面那个例子没有处理自动居中的情况,PR里进行了相应的兼容,并且运行demo大概看了下,没啥错误,请作者过目。不知道改动是否合理,作者也可以给出意见,谢谢。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant