问题
Why is it that when you repeatedly alter the visibility of a child view that is contained within a parent view and measure the parent view, Android returns wrong results?
I created a simple test: an XML file with only one ConstraintLayout and two TextViews. I will repeatedly alter the visibility of the last TextView to GONE and VISIBLE. Each time I alter the visibility of the TextView, I will measure the ConstraintLayout's width and height. To alter the visibility of the TextView, I set a click listener on the ConstraintLayout.
Here's the XML for said simple layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/testLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:padding="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorPrimary">
<TextView
android:id="@+id/iWillShow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textColor="@color/colorOnPrimary"/>
// This one will be hidden on click
<TextView
android:id="@+id/hideMe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="World"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iWillShow"
android:textColor="@color/colorOnPrimary" />
</androidx.constraintlayout.widget.ConstraintLayout>
In my Kotlin file, I have the following:
testLayout.setOnClickListener {
val matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec((it.parent as View).width, View.MeasureSpec.EXACTLY)
val wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
hideMe.visibility = View.VISIBLE
it.measure(matchParentMeasureSpec, wrapContentMeasureSpec)
Log.d("TEST LAYOUT", it.measuredWidth.toString() + " " + it.measuredHeight.toString())
hideMe.visibility = View.GONE
it.measure(matchParentMeasureSpec, wrapContentMeasureSpec)
Log.d("TEST LAYOUT", it.measuredWidth.toString() + " " + it.measuredHeight.toString())
hideMe.visibility = View.VISIBLE
it.measure(matchParentMeasureSpec, wrapContentMeasureSpec)
Log.d("TEST LAYOUT", it.measuredWidth.toString() + " " + it.measuredHeight.toString())
hideMe.visibility = View.GONE
it.measure(matchParentMeasureSpec, wrapContentMeasureSpec)
Log.d("TEST LAYOUT", it.measuredWidth.toString() + " " + it.measuredHeight.toString())
}
Upon clicking the parent view, the logs will return exactly these:
D/TEST LAYOUT: 1080 186
D/TEST LAYOUT: 1080 135
D/TEST LAYOUT: 1080 186
D/TEST LAYOUT: 1080 186
Obviously, the above logs are incorrect. It should have returned D/TEST LAYOUT: 1080 135
on the last line. However, that doesn't seem to be the case. Furthermore, it also caused an erroneous display. The height of the parent view will be the following (this is wrong, it should have been smaller):
When I tried only setting the visibility of the TextView to GONE without the measuring (like this):
testLayout.setOnClickListener {
hideMe.visibility = View.GONE
}
It returns the correct display of height like below:
Why does the above happen? What's the process behind it? The problem occurs after setting GONE -> VISIBLE once. After one occurrence of setting GONE -> VISIBLE, setting it to GONE -> VISIBLE -> GONE ... will produce that error.
来源:https://stackoverflow.com/questions/60294063/repeatedly-altering-visibility-of-a-child-view-and-measuring-parent-view-causes