Android - how to make a scrollable constraintlayout?

I want to make a layout that lets me scroll down using constraint layout, but I don't know how to go about it. Should the ScrollView be the parent of the ConstraintLayout like this?

<?xml version="1.0" encoding="utf-8"?>

<ScrollView 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"
    android:fillViewport="true">

<android.support.constraint.ConstraintLayout
    android:id="@+id/Constraint"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Or the other way around? Maybe someone can point me to a good tutorial on this or give an example, I can't seem to find one.

Also, I don't know if this is a bug or some configuration that I don't have set up but I've seen images like this one :

enter image description here

where there are some components outside the blueprint "blue rectangle" yet they are visible, while on my side if I place a component on the "white space" I can't see it or move it anywhere, and it appears on the component tree.

UPDATE :

I found a way to make the constraint layout scrollable in the design tool, using a horizontal guideline to push down the constraint layout border and extend it beyond the device, after that, you can use the guideline as the new bottom of the constraint layout to anchor the components.


It seems that it is working, I don't know what dependency you were working with but in this one

compile 'com.android.support.constraint:constraint-layout:1.0.2'

Is working, this is what I did

<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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"
    tools:context=".MainActivity">

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.design.widget.TextInputLayout
            android:id="@+id/til_input"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:hint="Escriba el contenido del archivo"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toLeftOf="@+id/btn_save"
            app:layout_constraintTop_toTopOf="@id/btn_save"
            app:layout_constraintVertical_chainStyle="spread">

            <EditText
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </android.support.design.widget.TextInputLayout>

        <Button
            android:id="@+id/btn_save"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClickButtonSave"
            android:text="Guardar"
            app:layout_constraintLeft_toRightOf="@+id/til_input"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/txt_content"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="0dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/til_input"
            app:layout_constraintVertical_chainStyle="spread"
            app:layout_constraintVertical_weight="1" />

        <Button
            android:id="@+id/btn_delete"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:onClick="onClickButtonDelete"
            android:text="Eliminar"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/txt_content"
            app:layout_constraintVertical_chainStyle="spread" />

    </android.support.constraint.ConstraintLayout>

</ScrollView>

Scroll Topenter image description here

Scroll Bottomenter image description here


There is a type of constraint which breaks the scroll function:

Just make sure you are not using this constraint on any view when wanting your ConstraintLayout to be scrollable with ScrollView :

app:layout_constraintBottom_toBottomOf=“parent”

If you remove these your scroll should work.

Explanation:

Setting the height of the child to match that of a ScrollView parent is contradictory to what the component is meant to do. What we want most of the time is for some dynamic sized content to be scrollable when it is larger than a screen/frame; matching the height with the parent ScrollView would force all the content to be displayed into a fixed frame (the height of the parent) hence invalidating any scrolling functionality.

This also happens when regular direct child components are set to layout_height="match_parent".

If you want the child of the ScrollView to match the height of the parent when there is not enough content, simply set android:fillViewport to true for the ScrollView.


Use NestedScrollView with viewport true is working good for me

<android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">

        <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="700dp">

        </android.support.constraint.ConstraintLayout>

</android.support.v4.widget.NestedScrollView>

for android x use this

 <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
.....other views....

</androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.core.widget.NestedScrollView>

To summarize, you basically wrap your android.support.constraint.ConstraintLayout view in a ScrollView within the text of the *.xml file associated with your layout.

Example activity_sign_in.xml

<?xml version="1.0" encoding="utf-8"?>

<ScrollView 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"
    tools:context=".SignInActivity"> <!-- usually the name of the Java file associated with this activity -->

    <android.support.constraint.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"
        android:background="@drawable/gradient"
        tools:context="app.android.SignInActivity">

        <!-- all the layout details of your page -->

    </android.support.constraint.ConstraintLayout>
</ScrollView>

Note 1: The scroll bars only appear if a wrap is needed in any way, including the keyboard popping up.

Note 2: It also wouldn't be a bad idea to make sure your ConstraintLayout is big enough to the reach the bottom and sides of any given screen, especially if you have a background, as this will ensure that there isn't odd whitespace. You can do this with spaces if nothing else.