日历视图在 Recyclerview ViewHolder 中显示/消失仅在 Android 8、9 上出现问题

Nad*_*bal 8 android visibility android-recyclerview

我有一个包含 2 个或更多查看者的 recyclerview,

  1. 第一个浏览者只是顶部标题横幅
  2. 第二个 vlewholder 用于预订小部件,它有 3 个下拉菜单/详细菜单,包括CalendarView——全部在一个 viewhodler 中。

问题是 CalendarView 的高度相当大,当 CalendarView 稍微离开屏幕并且我折叠/消失日历时,它会折叠但仍然占用空间,就像下面的屏幕截图一样。但奇怪的是,它只发生在Android 8 & 9.

初始屏幕截图:

在此输入图像描述

问题截图(折叠简历后):

在此输入图像描述

相关代码如下:

Viewholder 项目的 ClickListener:

    val clickListener = View.OnClickListener {
        // irrelevant code //
        for (type in AllOptionsEnum.values()) {
                // Expand Selected and Collapse Others
            val detailView = this.root.findViewById<ViewGroup>(type.detailViewGroupId)
            val labelView = this.root.findViewById<TextView>(type.labelViewId)
            val checkBox = this.root.findViewById<CheckBox>(type.checkBoxId)

            if (detailView.visibility == View.VISIBLE) {
                // hide detailed view
                detailView.setVisible(show = false)
                checkBox.isChecked = false
            } else {
                // show
                detailView.setVisible(show = (type.labelViewGroupId == it.id))
                checkBox.isChecked = show = (type.labelViewGroupId == it.id)
                
            }
                
        // irrelevant code //
        }
    }
Run Code Online (Sandbox Code Playgroud)

编辑1: 扩展功能:

    fun View.setVisible(show: Boolean = true, invisible: Boolean = false) {
        if (show) this.visibility = View.VISIBLE
        else this.visibility = if (invisible) View.INVISIBLE else View.GONE
    }
Run Code Online (Sandbox Code Playgroud)

编辑2:

我尝试了另一种解决方案,即完全删除recyclerview并使用nestedscrollview重新构造整个屏幕,但它也具有相同的效果。

编辑3:

我也尝试过下面的代码,但结果相同

                // show detailView
                if(type==Enums.StayWithUsWidgetType.TYPE_CALENDAR){
                    // show detailview and children
                    this.calendarDetailView.children.forEach {
                        it.visible()
                    }
                }


                // Hide detailView and children 
                if(type==Enums.StayWithUsWidgetType.TYPE_CALENDAR){
                    // hide all
                    this.calendarDetailView.children.forEach {
                        it.gone()
                    }
                }
Run Code Online (Sandbox Code Playgroud)

Von*_*onC 3

我不确定Android Pie (2018)如何处理布局中的可见性更改,特别是具有复杂布局层次结构的 CalendarView。

但请注意,“ Android Pvisibilityawareimagebutton.setVisibility 只能从同一个库组调用”很明确:

最佳实践:android:visibility="Gone"

使用可见性消失意味着您的视图不会占用布局上的任何空间,而“不可见”将占用布局上不必要的空间

因此,请仔细检查您的detailView.setVisible()功能。理想情况下,它应该看起来像:

fun View.setVisible(show: Boolean) {
    this.visibility = if (show) View.VISIBLE else View.GONE
}
Run Code Online (Sandbox Code Playgroud)

所以,当你看到 时setVisible(show = false),就相当于visibility = View.GONE在该视图上进行了设置。然而,这是一个假设,因为您的问题中没有提供此方法的实现。


测试的一个可能的替代解决方案是将 包装CalendarView在另一个布局中,例如LinearLayoutFrameLayout,然后设置此包装器布局而不是其CalendarView本身的可见性。
这可能有助于确保在可见性发生变化时正确地重新绘制布局。

例如:

<LinearLayout
    android:id="@+id/calendarViewContainer"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <CalendarView
        android:id="@+id/calendarView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

在您的点击侦听器中,您现在可以切换可见性calendarViewContainer而不是calendarView

val detailView = this.root.findViewById<ViewGroup>(if (type == AllOptionsEnum.CALENDAR) R.id.calendarViewContainer else type.detailViewGroupId)
Run Code Online (Sandbox Code Playgroud)

如果问题仍然存在,另一个解决方法是requestLayout()在将可见性更改为 后使用方法GONE。这将告诉 Android 系统再次测量和布局视图层次结构,这可能会解决您的问题。

detailView.setVisible(show = false)
detailView.requestLayout()
Run Code Online (Sandbox Code Playgroud)

这不是最有效的方法,因为它可能会导致不必要的布局传递,但可能有必要解决 Android Pie (9) 上的这个特定问题。


关于编辑3:

// hide detailView
if(type==Enums.StayWithUsWidgetType.TYPE_CALENDAR){
    // hide detailview and children
    this.calendarDetailView.children.forEach {
        it.visible()
    }
}
// Hide detailView and children 
if(type==Enums.StayWithUsWidgetType.TYPE_CALENDAR){
    // hide all
    this.calendarDetailView.children.forEach {
        it.gone()
    }
}
Run Code Online (Sandbox Code Playgroud)

我看到您试图单独隐藏calendarDetailView( 我假设是ViewGroup包含您的CalendarView) 的每个孩子。但是,目前还不清楚您是否将其calendarDetailView本身的可见性设置为GONE

我更愿意看到这段代码,其中它calendarDetailView本身也设置为GONE

if(type == Enums.StayWithUsWidgetType.TYPE_CALENDAR){
    // hide all children
    this.calendarDetailView.children.forEach {
        it.visibility = View.GONE
    }

    // then hide the parent itself
    this.calendarDetailView.visibility = View.GONE
}
Run Code Online (Sandbox Code Playgroud)