This is my case I'm trying to solve:
So, my goal is:
View1
in centre if there is enough space, that means View2
isn't that wide as to overlap with View1.View2
is wide enough to make it impossible to keep View1
in centre without overlapping, then in this case move View1
more to the left.What I have already tried is this:
<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>
With these constraints I tell View2
to take at least 43% of parent's width and if that is not enough then just apply wrap_content
. And then in View1
just do:
app:layout_constraintEnd_toStartOf="@+id/view2"
The value 43% is just an estimation that would pretty much position View1
to the centre in the 1st case of the picture. But it's not very accurate in some devices.
So would there be a solution that would position View1
exactly in the centre for the 1st scenario, and then move it to the left if necessary?
This is not something that can be done with just XML, AFAIK. You can accomplish it with a little code, though.
Change the layout so view2 is constrained to the right of the ConstraintLayout and the right of view1 is constrained to the left of 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>
Now, place the following code in your main activity. (It can go elsewhere, but the main activity is used here for demo purposes.) This code will manipulate the right margin of view1 to place it either in the center (if it doesn't overlap with view2) or pushed to the left in case of overlap.
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
}
Now when view2 is short enough, view1 will be centered:
And when view2 is longer, view1 will be pushed to the side.