NestedScrollView内ConstraintLayout因TextView文本量差异导致布局不一致
我瞅你遇到的问题是在NestedScrollView嵌套的ConstraintLayout里,那个带绿色、红色圆点的地址区域,当左右两个TextView文本量差得比较大时,布局就乱了,但文本量相近的时候显示就正常。这事儿其实是因为你用layout_weight分配宽度的方式,在嵌套布局里结合wrap_content计算高度时容易出岔子,尤其是文本换行后,两个子LinearLayout的垂直对齐逻辑就混乱了,导致视觉上的不一致。
问题根源拆解
你当前的地址区域是外层LinearLayout(ll_address)占满父布局宽度,里面两个子LinearLayout各拿layout_weight="1"均分宽度,但子布局高度是wrap_content。当其中一个TextView文本太长换行后,对应的子布局高度会被拉长,而另一个子布局因为文本短高度低,默认垂直对齐是顶部,就会出现一边高一边低的情况,再加上ConstraintLayout和LinearLayout的测量逻辑交互,就会出现布局偏移的问题。
解决方案
给你两个靠谱的解决思路,选一个适合你的就行:
方案一:改用ConstraintLayout实现地址区域(推荐)
把原来的水平LinearLayout换成ConstraintLayout,用垂直Guideline均分宽度,同时精准控制左右两个区域的垂直对齐,避免layout_weight带来的测量问题:
<android.support.constraint.ConstraintLayout android:id="@+id/cl_address" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="15dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/view_divider"> <!-- 左侧绿色圆点+地址容器 --> <LinearLayout android:id="@+id/ll_origin" android:layout_width="0dp" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/guideline_address" app:layout_constraintTop_toTopOf="parent"> <TextView android:layout_width="15dp" android:layout_height="15dp" android:layout_marginTop="3dp" android:background="@drawable/circle_shape_green" /> <TextView android:id="@+id/tv_origin_address" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:text="" android:textColor="@color/black" android:textSize="13sp" /> </LinearLayout> <!-- 右侧红色圆点+地址容器 --> <LinearLayout android:id="@+id/ll_destination" android:layout_width="0dp" android:layout_height="wrap_content" android:gravity="right" android:orientation="horizontal" app:layout_constraintLeft_toRightOf="@+id/guideline_address" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="@id/ll_origin"> <TextView android:layout_width="15dp" android:layout_height="15dp" android:layout_marginLeft="5dp" android:layout_marginTop="3dp" android:background="@drawable/circle_shape_red" /> <TextView android:id="@+id/tv_destination_address" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="5dp" android:gravity="right" android:text="" android:textColor="@color/black" android:textSize="13sp" /> </LinearLayout> <!-- 垂直指引线,均分布局宽度 --> <android.support.constraint.Guideline android:id="@+id/guideline_address" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.5" /> </android.support.constraint.ConstraintLayout>
方案二:优化原有LinearLayout结构
如果你不想换布局,也可以给外层LinearLayout加上垂直居中对齐,同时修改子布局的高度和重力,让两个子布局不管文本高度如何都保持垂直居中:
<LinearLayout android:id="@+id/ll_address" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="15dp" android:orientation="horizontal" android:alignItems="center" <!-- 新增:让子布局垂直居中 --> app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/view_divider"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" <!-- 修改为match_parent --> android:layout_weight="1" android:orientation="horizontal" android:gravity="center_vertical"> <!-- 新增:内部元素垂直居中 --> <TextView android:layout_width="15dp" android:layout_height="15dp" android:layout_marginTop="3dp" android:background="@drawable/circle_shape_green" /> <TextView android:id="@+id/tv_origin_address" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:text="" android:textColor="@color/black" android:textSize="13sp" /> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" <!-- 修改为match_parent --> android:layout_weight="1" android:gravity="right|center_vertical" <!-- 修改为右对齐+垂直居中 --> android:orientation="horizontal"> <TextView android:layout_width="15dp" android:layout_height="15dp" android:layout_marginLeft="5dp" android:layout_marginTop="3dp" android:background="@drawable/circle_shape_red" /> <TextView android:id="@+id/tv_destination_address" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="5dp" android:gravity="right" android:text="" android:textColor="@color/black" android:textSize="13sp" /> </LinearLayout> </LinearLayout>
为啥推荐方案一?
ConstraintLayout的布局测量逻辑更清晰,在嵌套NestedScrollView这种可滚动布局里,稳定性比LinearLayout的权重分配更好,尤其是当布局内容复杂、文本长度变化大的时候,能避免很多意想不到的布局偏移问题。
内容的提问来源于stack exchange,提问作者Deven Singh

