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

问题描述 投票:0回答:2

我有一个包含 2 个或更多查看者的回收者视图,

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

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

Android 8 & 9

初始屏幕截图:

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

相关代码如下:

Viewholder Item 的 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 //
        }
    }

编辑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
    }

编辑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()
                    }
                }
android android-recyclerview visibility
2个回答
2
投票

我不确定 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
}

所以,当你看到

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


一个可能的替代测试解决方案是将

CalendarView
包装在另一个布局中,例如
LinearLayout
FrameLayout
,然后设置此包装器布局的可见性,而不是
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>

在点击侦听器中,您现在可以切换

calendarViewContainer
而不是
calendarView
的可见性:

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

如果问题仍然存在,另一种解决方法是在将可见性更改为

requestLayout()
后使用
GONE
方法。这将告诉 Android 系统再次测量和布局视图层次结构,这可能会解决您的问题。

detailView.setVisible(show = false)
detailView.requestLayout()

这不是最有效的方法,因为它可能会导致不必要的布局传递,但可能有必要在 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()
    }
}

我看到您试图单独隐藏

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
}

0
投票

您可以尝试以编程方式设置 Calenderview 高度,如下所示,这可以帮助您显示该视图的额外空间。


if(type==Enums.StayWithUsWidgetType.TYPE_CALENDAR){
                    // setup height when needed
                    this.calendarDetailView.children.forEach {
                        calendarDetailView.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
                    }
                }

© www.soinside.com 2019 - 2024. All rights reserved.