ConstraintLayout中的GONE视图占据空间。

10

我有一个ViewHolder,其中标题在顶部,并且在特定情况下该标题变为可见状态。在大多数其他情况下,标题被设置为GONE。问题是,当标题被设置为GONE时,它的高度仍然被计算,并且其他视图会以不同的方式展开(之间有更多的空间)。

这是布局蓝图:

blueprint

解释如下:

  1. 标题受到顶部、左侧和右侧的限制。
  2. 下面的两个视图处于紧凑链中,限制为标题在顶部,ImageView在右侧,父级在左侧和底部。

这是布局检查器的屏幕截图,突出显示了设置为GONE的标题视图:

enter image description here

根据文档,当将标题视图设置为GONE时,应将其缩小到点,并仍应将其他视图的约束条件应用于其上,但是由于它被设置为wrap_content,因此标题不应占用布局空间或影响ConstraintLayout的高度。

在此检查器屏幕截图中,实际发生了什么并不清楚。标题不可见,底部视图明显受限于父级顶部,但是在检查器中显示的标题仍然是全宽度,并具有指定的高度。

我不确定这是一个错误还是我应该强制ConstraintLayout重新测量自身。

XML UPDATE:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">


    <TextView
        android:id="@+id/list_item_step_conversion_tv_header"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@color/gray_very_light"
        android:padding="@dimen/activity_vertical_margin"
        android:text="@string/favorites"
        android:textColor="@android:color/black"
        android:textSize="@dimen/default_text_size"
        android:textStyle="bold"
        android:visibility="gone"
        tools:visibility="visible"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/list_item_step_conversion_tv_title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:layout_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:ellipsize="end"
        android:maxLines="1"
        android:textColor="@color/gray_dark"
        android:textSize="@dimen/medium_text_size"
        app:layout_constraintBottom_toTopOf="@+id/list_item_step_conversion_tv_description"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/list_item_step_conversion_iv_favorite"
        app:layout_constraintTop_toBottomOf="@+id/list_item_step_conversion_tv_header"
        app:layout_constraintVertical_chainStyle="packed"
        tools:text="Bicycling - light (10-11.9 mph)"/>

    <TextView
        android:id="@+id/list_item_step_conversion_tv_description"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="0dp"
        android:layout_marginRight="16dp"
        android:layout_marginTop="4dp"
        android:ellipsize="end"
        android:maxLines="1"
        android:textColor="@android:color/black"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="@+id/list_item_step_conversion_tv_title"
        app:layout_constraintRight_toLeftOf="@+id/list_item_step_conversion_iv_favorite"
        app:layout_constraintTop_toBottomOf="@+id/list_item_step_conversion_tv_title"
        tools:text="182 steps/minute"/>

    <ImageView
        android:id="@+id/list_item_step_conversion_iv_favorite"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="0dp"
        android:layout_marginRight="24dp"
        android:layout_marginTop="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/list_item_step_conversion_tv_header"
        app:srcCompat="@drawable/ic_not_liked"/>    
</android.support.constraint.ConstraintLayout>

更新2

经过进一步观察,这个问题仅在RecyclerView.Adapter中调用notifyDataSetChanged后发生。以下是单击其中一个项目的favorite图标之前和之后的布局状态的屏幕截图。 enter image description here

屏幕截图说明:

  • 左侧为position: 2上可见header视图的ViewHolder。上面的项目正常显示。
  • 单击favorite图标(值为242的项目)后,position: 1上的ViewHolder成为具有可见header视图的ViewHolder,而position: 2上的ViewHolderheader视图设置为GONE。我原本期望ViewHolder的高度会减小,并与position: 0上的ViewHolder具有相同的高度。

考虑到这个ViewHolder在先前的状态下已设置headerVISIBLE,这可能与回收有关,但不确定。


请发布您的 XML。 - Abbas
@Abbas 确定,已添加。 - bajicdusko
嗯。底部的项目看起来像是两个TextView使用了扩展链样式而不是紧凑的样式。对我来说,现在已经太晚了,希望明天能看一下。这是基于一个设备,并且看起来一样(当然,高亮视图的红色标记除外)?你正在使用ConstraintLayout 1.0.2吗? - Wolfram Rittmeyer
嘿,Wolfram,谢谢回复。我已经更新了问题,并附加了更多的截图。我认为仍然使用了压缩链,但是回收的viewholder的高度没有减小,实际项之间的空间比预期的要大。当然是1.0.2版本。 - bajicdusko
@bajicdusko 我认为这里发生的情况是元素被正确标记为已删除,因此另外两个元素 - 由于它们在链中 - 被重新定位以利用空间,因此更加分散(请参见您的原始截图)。基本上,它的行为就像布局的wrap_content没有被尊重或调用一样。我怀疑这是由于视图回收引起的一些诡计。 - Nicolas Roard
@NicolasRoard 是的,你说得对,在viewholder回收后,wrap_content在链中不被尊重。我已经排除了链并进行了测试,它的行为是正确的。老实说,我没有注意到原始截图和最后一个截图是不同的(不知道为什么..)。Wolfram说第一个截图看起来像链:spread,他是对的。第二个肯定是packed。此时,我不确定上面的行为是否正确,但对我来说仍然有意义(在GONE上调整大小,应用链)。如果您认为这是一个错误,我可以为您创建一个或关闭问题:)。谢谢 - bajicdusko
3个回答

2
我已经解决了这个问题,方法是在我的适配器的#getView中通常调用binding.executePendingBindings()之后,在结尾处调用view.requestLayout()
*我现在正在使用老式的Adapter,所以你应该搜索RecyclerView.Adapter的相当部分,可能是#onBindViewHolder()

0

看起来布局实际上是正确的——忽略检查器中已消失对象的框架,当小部件被标记为已消失时,我们不会再次布局它,因为它将被跳过(在 Studio 中我们会这样做,以提供更简单的方式来查看正在发生的事情,但在真实设备上这样做没有意义)。

您使用的 ConstraintLayout 版本是哪个?我似乎在这里得到了正确的行为:

enter image description here

在将第一个元素标记为“gone”之后:

enter image description here


谢谢Nicolas的回复。我已经更新了问题并添加了一些解释。当RecyclerView第一次显示时,布局行为是正确的。看起来在回收具有可见标题的ViewHolder时存在问题。我希望我没有漏掉什么明显的东西。请查看上面的“UPDATE 2”部分。我正在使用1.0.2版本。 - bajicdusko

-1
我的解决方法是将对象的初始可见性设置为“gone”,然后通过代码更改其可见性。
像这样:
我的XML:
<androidx.appcompat.widget.AppCompatTextView
    android:id="@+id/tvMyobject"
    style="@style/myStyle"
    tools:text="@string/dummy_text"
    android:textAlignment="center"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@id/anyotherobject"
    android:visibility="gone"
/>

我的活动:

if (isSomethingToShow) {
    tvMyobject.setVisibility(View.VISIBLE);
    tvMyobject.setText(R.string.my_string_to_show);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接