6

I have the following layout. Notice Z is positioned below Y, but constrained to the bottom. There is a nice gap gap between Y and Z, afforded by the excess vertical space. This is my desired and actual behavior when there is excess vertical space.

enter image description here

However, I run out of excess vertical space when the keyboard is shown.

Desired Behavior (no excess vertical space) When I run out of vertical space, I would like the following to occur: X (ScrollView), shrinks to fill the remaining space, allowing Y and Z to be displayed at full size.

enter image description here

Actual Behavior (no excess vertical space) Y shrinks instead.

enter image description here

My source is below. How can I modify it to get my desired behavior in both scenarios (excess vertical space and no excess vertical space)?

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

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#fbe9e7"
            android:gravity="center"
            android:text="X"
            android:textSize="96sp">

        </TextView>
    </ScrollView>

    <TextView
        android:id="@+id/text_Y"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#f3e5f5"
        android:gravity="center"
        android:text="Y"
        android:textSize="96sp"
        app:layout_constraintTop_toBottomOf="@+id/scrollView" />

    <TextView
        android:id="@+id/text_Z"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#e1f5fe"
        android:gravity="center"
        android:text="Z"
        android:textSize="96sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_Y"
        app:layout_constraintVertical_bias="1" />

</androidx.constraintlayout.widget.ConstraintLayout>

The issue largely stems from the X scrollview needing to be 0dp when vertical space is limited, but wrap_content when there is excess vertical space

Note: you can demo how the layout will behave with less vertical space by dragging the bottom right corner accordingly in the preview pane for a layout in Android Studioenter image description here

ZakTaccardi
  • 12,212
  • 15
  • 59
  • 107

4 Answers4

3

try this

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constrainedHeight="true"
        app:layout_constraintBottom_toTopOf="@+id/text_Y"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0"
        app:layout_constraintVertical_chainStyle="packed">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#fbe9e7"
            android:gravity="center"
            android:text="X"
            android:textSize="96sp">

        </TextView>
    </ScrollView>

    <TextView
        android:id="@+id/text_Y"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#f3e5f5"
        android:gravity="center"
        android:text="Y"
        android:textSize="96sp"
        app:layout_constraintBottom_toTopOf="@+id/text_Z"
        app:layout_constraintTop_toBottomOf="@+id/scrollView"
        app:layout_constraintVertical_bias="0" />

    <TextView
        android:id="@+id/text_Z"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#e1f5fe"
        android:gravity="center"
        android:text="Z"
        android:textSize="96sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
fancyyou
  • 965
  • 6
  • 7
1

I would recommend a barrier constraint: https://developer.android.com/reference/android/support/constraint/Barrier

You would have the barrier be the top of the two bottom views, Z and the an empty view that goes from the parent bottom to the bottom of Y.

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

<ScrollView
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#fbe9e7"
        android:gravity="center"
        android:text="X"
        android:textSize="96sp">

    </TextView>
</ScrollView>

<TextView
    android:id="@+id/text_Y"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#f3e5f5"
    android:gravity="center"
    android:text="Y"
    android:textSize="96sp"
    app:layout_constraintTop_toBottomOf="@+id/scrollView" 
    app:layout_constraintBottom_topTopOf="@+barrier_bottom"/>

<androidx.constraintlayout.widget.Barrier
            android:id="@+id/barrier_bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:barrierDirection="bottom"
            app:constraint_referenced_ids="text_Z,spacer" />

<TextView
    android:id="@+id/spacer
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_constraintTop_topBottomOf="@+id/text_Y"
    app:layout_constraintBottom_toBottomOf="parent"/>

<TextView
    android:id="@+id/text_Z"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#e1f5fe"
    android:gravity="center"
    android:text="Z"
    android:textSize="96sp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintVertical_bias="1" />

</androidx.constraintlayout.widget.ConstraintLayout>
Cory Roy
  • 5,379
  • 2
  • 28
  • 47
0

As far as I tested my own solution, I found that your desired behaviour is not achievable. I've spent approximately 2 hours combining different variations of chains and another ConstraintLayout stuff. This is the only possible solution I've got. TextY and TextZ after resizing stay fully visible, but TextX doesn't resize staying the same height and hiding behind TextY.

Desired behaviour

Solution itself:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#fbe9e7"
            android:gravity="center"
            android:text="X"
            android:textSize="96sp">

        </TextView>
    </ScrollView>

    <TextView
        android:id="@+id/text_Y"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#f3e5f5"
        android:gravity="center"
        android:text="Y"
        android:textSize="96sp"
        app:layout_constraintBottom_toTopOf="@id/text_Z"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/scrollView"
        app:layout_constraintVertical_bias="1"
        app:layout_constraintVertical_chainStyle="spread_inside" />

    <TextView
        android:id="@+id/text_Z"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#e1f5fe"
        android:gravity="center"
        android:text="Z"
        android:textSize="96sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text_Y" />

</androidx.constraintlayout.widget.ConstraintLayout>

aspix
  • 425
  • 2
  • 9
0

The below code works as you would expect it to, have tested it personally. It is worth noting that the behavior you desire, i.e the scrollview changing its size when the text_y starts overlapping it, cannot be achieved with only a single constraint layout, so I've put the text_y and text_z in another constraint layout.

<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="match_parent">

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintHeight_max="wrap"
        app:layout_constraintBottom_toTopOf="@id/constraint"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_chainStyle="spread_inside"
        app:layout_constraintVertical_bias="0">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#fbe9e7"
            android:gravity="center"
            android:text="X"
            android:textSize="96sp">

        </TextView>
    </ScrollView>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/constraint"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintHeight_min="wrap"
        app:layout_constraintTop_toBottomOf="@id/scrollView"
        app:layout_constraintBottom_toBottomOf="parent">  
        <TextView
            android:id="@+id/text_Y"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#f3e5f5"
            android:gravity="center"
            android:text="Y"
            android:textSize="96sp"
            app:layout_constraintVertical_chainStyle="spread_inside"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toTopOf="@id/text_Z"/>

        <TextView
            android:id="@+id/text_Z"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#e1f5fe"
            android:gravity="center"
            android:text="Z"
            android:textSize="96sp"
            app:layout_constraintTop_toBottomOf="@id/text_Y"
            app:layout_constraintBottom_toBottomOf="parent"/>
    </androidx.constraintlayout.widget.ConstraintLayout>


</androidx.constraintlayout.widget.ConstraintLayout>
Darshan Miskin
  • 844
  • 14
  • 25