Android ConstraintLayout - 当有足够的空间时将视图定位到中心 space 并在必要时移动到边缘

Android ConstraintLayout - position view to center when there is enough space and move to edges if necessary

这是我要解决的案例:

所以,我的目标是:

  1. 如果有足够的 space,要让 View1 居中,这意味着 View2 没有那么宽,无法与 View1 重叠。
  2. 如果 View2 足够宽以至于无法将 View1 保持在中间而不重叠,那么在这种情况下将 View1 向左移动更多。

我已经尝试过的是:

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/view1"
        android:layout_width="wrap_content"
        android:layout_height="44dp"
        android:layout_marginEnd="8dp"
        android:src="@drawable/ic_img"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/view2"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="wrap" />

    <View
        android:id="@+id/view2"
        android:layout_width="0dp"
        android:background="@color/black"
        android:layout_height="50dp"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_min="wrap"
        app:layout_constraintWidth_percent="0.43" />

</androidx.constraintlayout.widget.ConstraintLayout>

在这些限制条件下,我告诉 View2 至少占用父级宽度的 43%,如果这还不够,那么就应用 wrap_content。然后在 View1 中执行:

app:layout_constraintEnd_toStartOf="@+id/view2"

43% 只是估计值,在图片的第一种情况下,View1 几乎位于中心位置。但它在某些设备上不是很准确。

那么,是否有一种解决方案可以将 View1 准确定位在第一种情况的中心,然后在必要时将其移至左侧?

这不是 XML 所能完成的事情,AFAIK。不过,您可以使用一些代码来完成它。

更改布局,将 view2 限制在 ConstraintLayout 的右侧,将 view1 的右侧限制在 view2 的左侧。

<androidx.constraintlayout.widget.ConstraintLayout 
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <View
        android:id="@+id/view1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginEnd="8dp"
        android:background="#2196F3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/view2"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:id="@+id/view2"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:background="#FF5722"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

现在,将以下代码放入主 activity。 (它可以放在其他地方,但主要的 activity 在这里用于演示目的。)此代码将操纵 view1 的右边距以将其放置在中心(如果它不与 view2 重叠)或推入在重叠的情况下向左。

    val layout = findViewById<ConstraintLayout>(R.id.layout)
    layout.doOnNextLayout {
        val view1 = findViewById<View>(R.id.view1)
        val view2 = findViewById<View>(R.id.view2)
        val view1Margin =
            if ((layout.width + view1.width) / 2 < view2.x) {
                // view1 can be centered.
                (view2.x - (layout.width + view1.width) / 2).toInt()
            } else {
                // view1 is pushed to left of center. 16dp is the right margin now.
                (16 * resources.displayMetrics.density).toInt()
            }
        val lp = view1.layoutParams as ViewGroup.MarginLayoutParams
        lp.rightMargin = view1Margin
        view1.layoutParams = lp
    }

现在当 view2 足够短时,view1 将居中:

而当view2较长时,view1会被推到一边