自定义对话框问题中的约束布局
Posted
技术标签:
【中文标题】自定义对话框问题中的约束布局【英文标题】:Constraint layout in Custom Dialog problem 【发布时间】:2021-09-07 03:24:06 【问题描述】:我有这样的自定义对话框的 XML 文件:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingHorizontal="15dp"
android:paddingVertical="10dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_header"
android:layout_
android:layout_
app:layout_constraintTop_toTopOf="parent"
android:paddingBottom="15dp">
<TextView
style="@style/tv_big"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@id/cl_header"
android:layout_
android:layout_
android:textStyle="bold"
android:text="Filter"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/bt_reset"
android:textColor="@color/black"
android:layout_
android:layout_
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="@id/cl_header"
android:text="RESET FILTERS"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_distance"
app:layout_constraintTop_toBottomOf="@id/cl_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_
android:layout_>
<TextView
android:id="@+id/tv_distance_title"
style="@style/tv_medium"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_
android:layout_
android:text="Distance range"/>
<TextView
android:id="@+id/tv_distance_result"
android:layout_
android:layout_
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="@id/tv_distance_title"
app:layout_constraintLeft_toRightOf="@id/tv_distance_title"
app:layout_constraintRight_toRightOf="parent"
android:background="#ddd"
android:padding="3dp"
android:textColor="#333"
android:text="0 km - 500km"/>
<com.google.android.material.slider.RangeSlider
android:id="@+id/slider_distance"
app:layout_constraintTop_toBottomOf="@id/tv_distance_title"
android:layout_
android:layout_
app:labelBehavior="gone"
android:stepSize="1.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_location"
android:layout_
android:layout_
app:layout_constraintTop_toBottomOf="@id/cl_distance"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:id="@+id/tv_location_title"
style="@style/tv_medium"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_
android:layout_
android:text="Location"/>
<EditText
android:id="@+id/et_location"
android:layout_
android:layout_
app:layout_constraintTop_toBottomOf="@id/tv_location_title"
android:hint="@string/filter_location_et_hint" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_
android:layout_
app:layout_constraintTop_toBottomOf="@id/cl_location"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<Button
android:id="@+id/bt_cancel"
android:backgroundTint="#ccc"
android:textColor="@color/black"
android:layout_
android:layout_
android:layout_marginStart="20dp"
android:text="CANCEL"/>
<Button
android:id="@+id/bt_save"
android:layout_
android:layout_
android:text="save"
android:layout_marginHorizontal="20dp"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Android Studio 是这样渲染的:
这就是我希望在我的对话框中拥有的内容。
但是:
在物理设备和模拟器上,它看起来与在 Android Studio 中不同:
我的问题是:如何在左侧放置“过滤器”标题,并使位置 EditText 与父级匹配(在工作应用程序中)?
【问题讨论】:
您必须使用RelativeLayout(使用android:layout_toLeftOf)或LinearLayout(将其方向设置为水平并设置权重)。 与此答案无关,但 ConstraintLayout 的全部意义在于删除您拥有的这些嵌套布局。如果您要嵌套多个 ConstraintLayouts,那么只需使用 LinearLayouts。您可以在一个 ConstraintLayout 中设计整个对话框。 对了,你为什么用了这么多嵌套?我相信只有一个约束布局就足够了。 这是一个link 以获得更好的布局代码,也许这可能会对您有所帮助。是的,请考虑根据您的选择调整一些边距和内容:) 【参考方案1】:其他人说的都是正确的,保持布局平坦对性能和这些情况都有好处,您想快速找出为什么布局没有按照您想要的方式布局;)
试试这个:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_
android:layout_
android:paddingHorizontal="15dp"
android:paddingVertical="10dp">
<TextView
android:layout_
android:layout_
android:gravity="start"
android:text="Filter"
app:layout_constraintBottom_toBottomOf="@id/bt_reset"
app:layout_constraintEnd_toStartOf="@id/bt_reset"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/bt_reset" />
<com.google.android.material.button.MaterialButton
android:id="@+id/bt_reset"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_
android:layout_
android:text="RESET FILTERS"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_distance_title"
android:layout_
android:layout_
android:text="Distance range"
app:layout_constraintBottom_toBottomOf="@id/tv_distance_result"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_distance_result" />
<TextView
android:id="@+id/tv_distance_result"
android:layout_
android:layout_
android:layout_marginTop="15dp"
android:background="#ddd"
android:gravity="center"
android:paddingHorizontal="18dp"
android:paddingVertical="3dp"
android:text="0 km - 500km"
android:textColor="#333"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/bt_reset" />
<com.google.android.material.slider.RangeSlider
android:id="@+id/slider_distance"
android:layout_
android:layout_
android:stepSize="1.0"
app:labelBehavior="gone"
app:layout_constraintTop_toBottomOf="@id/tv_distance_result" />
<TextView
android:id="@+id/tv_location_title"
android:layout_
android:layout_
android:text="Location"
app:layout_constraintTop_toBottomOf="@id/slider_distance" />
<EditText
android:id="@+id/et_location"
android:layout_
android:layout_
android:hint="test"
app:layout_constraintTop_toBottomOf="@id/tv_location_title" />
<Button
android:id="@+id/bt_cancel"
android:layout_
android:layout_
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:backgroundTint="#ccc"
android:text="CANCEL"
android:textColor="@color/colorBlack"
app:layout_constraintEnd_toStartOf="@id/bt_save"
app:layout_constraintTop_toBottomOf="@id/et_location" />
<Button
android:id="@+id/bt_save"
android:layout_
android:layout_
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:text="save"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/et_location" />
</androidx.constraintlayout.widget.ConstraintLayout>
【讨论】:
您的解决方案几乎可以工作,但是我在回答中写到的 LinearLayout 存在一个问题(我同时找到了解决方案)【参考方案2】:我将内部 ConstraintLayouts 更改为 LinearLayouts 并使用权重。我还使用this trick 填充例如之间的空间。 “过滤器”标题和“重置过滤器”按钮。
ll_location LinearLayout 也存在问题 - 它与父级不匹配。 我换了:
<LinearLayout
android:id="@+id/ll_location"
android:layout_
android:layout_
app:layout_constraintTop_toBottomOf="@id/ll_distance_ext"
android:orientation="vertical">
<!-- content -->
</LinearLayout>
进入:
<LinearLayout
android:id="@+id/ll_location"
android:layout_
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_
app:layout_constraintTop_toBottomOf="@id/ll_distance_ext"
android:orientation="vertical">
<!-- content -->
</LinearLayout>
然后它起作用了。
我不想使用 flat 布局(为什么我使用嵌套布局)的原因是恕我直言,flat 布局使代码更难维护。 将视图拆分为组后,无论组中有多少视图,都可以轻松替换它们。
我的解决方案:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingHorizontal="15dp"
android:paddingVertical="10dp">
<LinearLayout
android:id="@+id/ll_header"
android:layout_
android:layout_
app:layout_constraintTop_toTopOf="parent"
android:paddingBottom="15dp">
<TextView
style="@style/tv_big"
android:layout_
android:layout_
android:textStyle="bold"
android:text="Filter"/>
<View
android:layout_
android:layout_
android:layout_weight="1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/bt_reset"
android:textColor="@color/black"
android:layout_
android:layout_
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:text="reset filters"/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_distance_ext"
app:layout_constraintTop_toBottomOf="@id/ll_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_
android:layout_
android:orientation="vertical">
<LinearLayout
android:layout_
android:layout_
android:orientation="horizontal">
<TextView
android:id="@+id/tv_distance_title"
style="@style/tv_medium"
android:layout_
android:layout_
android:text="Distance range"/>
<View
android:layout_
android:layout_
android:layout_weight="1" />
<TextView
android:id="@+id/tv_distance_result"
android:layout_
android:layout_
android:textAlignment="center"
android:background="#ddd"
android:padding="3dp"
android:textColor="#333"
android:text="0 km - 500km"/>
</LinearLayout>
<com.google.android.material.slider.RangeSlider
android:id="@+id/slider_distance"
android:layout_
android:layout_
app:labelBehavior="gone"
android:stepSize="1.0" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_location"
android:layout_
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_
app:layout_constraintTop_toBottomOf="@id/ll_distance_ext"
android:orientation="vertical">
<TextView
android:id="@+id/tv_location_title"
style="@style/tv_medium"
android:layout_
android:layout_
android:text="Location"/>
<EditText
android:id="@+id/et_location"
android:layout_
android:layout_
android:hint="@string/filter_location_et_hint" />
</LinearLayout>
<LinearLayout
android:layout_
android:layout_
app:layout_constraintTop_toBottomOf="@id/ll_location"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<Button
android:id="@+id/bt_cancel"
android:backgroundTint="#ccc"
android:textColor="@color/black"
android:layout_
android:layout_
android:layout_marginStart="20dp"
android:text="cancel"/>
<Button
android:id="@+id/bt_save"
android:layout_
android:layout_
android:text="save"
android:layout_marginHorizontal="20dp"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
【讨论】:
我不知道维护的难度,但它对性能有明显的影响。不仅嵌套的视图层次结构和太多的 ViewGroup,而且还有一些额外的成本,比如水平 LinearLayout 导致double layout taxation。以上是关于自定义对话框问题中的约束布局的主要内容,如果未能解决你的问题,请参考以下文章
自定义 UITableViewCell 的自动布局约束在运行时失败
自定义布局中约束更改的动画 UICollectionView 项目
约束布局中的 ViewPager 选项卡式活动在底部被剪切以用于 recyclerview