英文:
Calendar View show/gone inside Recyclerview ViewHolder Issue on Android 8, 9 only
问题
-
我有一个具有2个或更多个视图持有者的 RecyclerView。
-
第一个视图持有者只是顶部的横幅。
-
第二个视图持有者是用于预订小部件的,其中包括3个下拉菜单/详细菜单,包括
CalendarView
,全部位于一个视图持有者中。 -
问题是 CalendarView 的高度相当大,当 CalendarView 稍微超出屏幕并且我折叠/隐藏日历时,它会折叠,但仍然占据空间,就像下面的截图一样。但奇怪的是,这只发生在 Android 8 和 9 中。
-
初始截图:
-
问题截图 (折叠 CV 后):
-
相关代码如下:
视图持有者项的点击监听器:
val clickListener = View.OnClickListener { // 不相关的代码 // for (type in AllOptionsEnum.values()) { // 展开选定的项目并折叠其他项目 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) { // 隐藏详细视图 detailView.setVisible(show = false) checkBox.isChecked = false } else { // 显示 detailView.setVisible(show = (type.labelViewGroupId == it.id)) checkBox.isChecked = show = (type.labelViewGroupId == it.id) } // 不相关的代码 // } }
编辑 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 并使用嵌套滚动视图重新构建整个屏幕,但效果也相同。
编辑 3:
我也尝试了以下代码,但结果相同
// 显示详细视图 if(type==Enums.StayWithUsWidgetType.TYPE_CALENDAR){ // 显示详细视图及其子视图 this.calendarDetailView.children.forEach { it.visible() } } // 隐藏详细视图及其子视图 if(type==Enums.StayWithUsWidgetType.TYPE_CALENDAR){ // 隐藏所有 this.calendarDetailView.children.forEach { it.gone() } }
英文:
I have a recyclerview with 2 or more viewholders,
- 1st Viewholder is just top heading banner
- 2nd vlewholder is for booking widget which has 3 dropdowns/detail menus including
CalendarView
-- All in one viewhodler.
Issue is CalendarView is quite big in height and when the CalendarView is slightly off the screen and I collapse/gone the calendar it is collapsing but still taking space just like below screenshots. But Strange thing is that its occurring only in Android 8 & 9
.
Initial Screenshot:
Issue Screenshot (After Collapsing CV):
Relevant Code is below:
Viewholder Item's 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 //
}
}
Edit 1:
Extension Func:
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
}
Edit 2:
> I have tried another solution i.e. to remove the recyclerview completely and re-constructed the whole screen using nestedscrollview but it also has same effects.
Edit 3:
I have tried below code also but same result
// 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()
}
}
答案1
得分: 3
I am not sure how Android Pie (2018) is handling visibility changes in layouts, particularly with the CalendarView which has a complex layout hierarchy.
But do note that "Android P visibilityawareimagebutton.setVisibility can only be called from the same library group" is clear:
Best practice:
android:visibility="Gone"
Using visibility gone means your view does not take up any space on your layout while "invisible" will take up unnecessary space on your layout.
So double-check your detailView.setVisible()
function. Ideally, it should look like:
fun View.setVisible(show: Boolean) {
this.visibility = if (show) View.VISIBLE else View.GONE
}
So, when you see setVisible(show = false)
, it is equivalent to setting visibility = View.GONE
on that view. This is, however, an assumption, as the implementation of this method is not provided in your question.
A possible alternative solution to test would be to wrap the CalendarView
in another layout such as LinearLayout
or FrameLayout
, and then set the visibility of this wrapper layout instead of the CalendarView
itself.
That might help ensure the layout is redrawn correctly when visibility changes.
For example:
<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>
In your click listener, you would now toggle visibility of calendarViewContainer
instead of calendarView
:
val detailView = this.root.findViewById<ViewGroup>(if (type == AllOptionsEnum.CALENDAR) R.id.calendarViewContainer else type.detailViewGroupId)
If the problem still persists, another workaround is to use requestLayout()
method after changing the visibility to GONE
. That will tell the Android system to measure and layout the view hierarchy again, which might fix your issue.
detailView.setVisible(show = false)
detailView.requestLayout()
That is not the most efficient way since it could lead to unnecessary layout passes, but it might be necessary to work around this specific issue on Android Pie (9).
Regarding Edit 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()
}
}
I see you are attempting to hide each child of the calendarDetailView
(which I assume is the ViewGroup
that contains your CalendarView
) individually. However, it is still not clear if you are setting the visibility of the calendarDetailView
itself to GONE
.
I would prefer to see this code, where the calendarDetailView
itself is also set to 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
}
英文:
I am not sure how Android Pie (2018) is handling visibility changes in layouts, particularly with the CalendarView which has a complex layout hierarchy.
But do note that "Android P visibilityawareimagebutton.setVisibility can only be called from the same library group" is clear:
> Best practice: android:visibility="Gone"
>
> Using visibility gone means your view is does not take up any space on your layout while "invisible" will take up unnecessary space on your layout
So double-check your detailView.setVisible()
function. Ideally, it should look like:
fun View.setVisible(show: Boolean) {
this.visibility = if (show) View.VISIBLE else View.GONE
}
So, when you see setVisible(show = false)
, it is equivalent to setting visibility = View.GONE
on that view. This is, however, an assumption, as the implementation of this method is not provided in your question.
A possible alternative solution to test would be to wrap the CalendarView
in another layout such as LinearLayout
or FrameLayout
, and then set the visibility of this wrapper layout instead of the CalendarView
itself.
That might help ensure the layout is redrawn correctly when visibility changes.
For example:
<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>
In your click listener, you would now toggle visibility of calendarViewContainer
instead of calendarView
:
val detailView = this.root.findViewById<ViewGroup>(if (type == AllOptionsEnum.CALENDAR) R.id.calendarViewContainer else type.detailViewGroupId)
If the problem still persists, another workaround is to use requestLayout()
method after changing the visibility to GONE
. That will tell the Android system to measure and layout the view hierarchy again, which might fix your issue.
detailView.setVisible(show = false)
detailView.requestLayout()
That is not the most efficient way since it could lead to unnecessary layout passes, but it might be necessary to work around this specific issue on Android Pie (9).
Regarding Edit 3:
> kotlin
> // 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()
> }
> }
>
I see you are attempting to hide each child of the calendarDetailView
(which I assume is the ViewGroup
that contains your CalendarView
) individually. However, it is still not clear if you are setting the visibility of the calendarDetailView
itself to GONE
.
I would prefer to see this code, where the calendarDetailView
itself is also set to 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
}
答案2
得分: 0
你可以尝试通过以下方式以编程方式设置日历视图的高度,这可以帮助您显示该视图的额外空间。
if (type == Enums.StayWithUsWidgetType.TYPE_CALENDAR) {
// 需要时设置高度
this.calendarDetailView.children.forEach {
calendarDetailView.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
}
}
英文:
You can try with setting the Calenderview height programatically like below that can help you in showing extra space of that view.
if(type==Enums.StayWithUsWidgetType.TYPE_CALENDAR){
// setup height when needed
this.calendarDetailView.children.forEach {
calendarDetailView.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论