ConstraintLayout: center view on full screen but limit width to not overlap with side views
Asked Answered
S

1

3

I have a toolbar like component implementation, that I'm having trouble with the layout in all situations. It has a left icon, a title and a right menu/button. I need the title to be centered on the full screen (or at least the full width of the layout) but also to not overlap with the other components. So the width of the title would have to be constrained by the left icon and the right button.

I have two intermediary solutions but can't seem to find a way to combine them.

One is to center the title on the screen. The problem here is that the title overlaps with the right button (and would overlap with the left icon too, if large enough ...). Here is the layout XML:

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/bottomSheetHeaderIcon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:focusable="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/bottomSheetHeaderTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textAlignment="center"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="My also very very very very very long title" />

    <TextView
        android:id="@+id/right_action"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Really long string longer"/>
</androidx.constraintlayout.widget.ConstraintLayout>

The other is to center the title between the left icon and the right button. Now there is no overlap, but the title is not centered correctly. Since the two side elements have very different sizes, the title is only centered between them, which is no good. Here is the same layout with the constraints for this case:

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/bottomSheetHeaderIcon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:focusable="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/bottomSheetHeaderTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textAlignment="center"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/right_action"
        app:layout_constraintStart_toEndOf="@+id/bottomSheetHeaderIcon"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="My also very very very very very long title" />

    <TextView
        android:id="@+id/right_action"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Really long string longer"/>
</androidx.constraintlayout.widget.ConstraintLayout>

I'm trying to get away with just a XML layout solution, without having to do programmatically detect overlaps and change the layout.

Solutions with other layouts would also work, if they exist.

The problem is the same as the questions here and here, but I'm hoping that by giving more detail, this one gets an accepted solution.

Sennight answered 11/9, 2020 at 13:43 Comment(5)
what if right menu button have long text then what you want to do?Flasher
how much space left and right icon should take place in your case?Flasher
Left icon has a pretty fixed size, but may change. The right menu/button may change size significantly, in particular because of internationalization. The right button should show full content (no ellipsize, no width restrictions). In the ideal solution, none of the sizes are fixed. And, if there is enough space, everything shows correctly in one line. The title may have multiple lines. Are these clarifications helpful @ShwetaChauhan?Sennight
yes clear but without limiting right side text we can't get title in center. See, this image you can get like this : ibb.co/thkz6Zx If this okay for you then I can add codeFlasher
Nope, interesting solution, but not what I want.Sennight
S
0

Here is a programatic answer to this question, that is what I'm using for now, but I'd really like a layout solution ...

I use the first layout, centered on the screen, and, as this is part of a custom view for me, add the following code to the constructor (title is a reference to bottomSheetHeaderTitle and rightAction is right_action, the left icon is assumed to always be smaller than the right action text).

        viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                if (title.width > 0) {
                    if (title.right > rightAction.x) {
                        title.maxWidth = (2.0 * (width / 2.0 - (width - rightAction.x))).toInt()
                    }
                    viewTreeObserver.removeOnGlobalLayoutListener(this)
                }
            }
        })

This code detects if the title overlaps the right action, and, if it does, adds a max width to it. The max width is the double of the distance between the center of the screen and the beginning of the right action.

Sennight answered 11/9, 2020 at 22:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.