170

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.

Abhimanyu
  • 1,720
  • 1
  • 11
  • 35
gtovar
  • 1,841
  • 2
  • 7
  • 6

17 Answers17

90

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

Sagar Chapagain
  • 1,476
  • 2
  • 14
  • 21
sealroto
  • 1,151
  • 8
  • 12
  • 3
    thanks, the problem was that I couldnt scroll on the preview, so building something there was imposible but I found out that using a guideline I can pull down the layout to make empty scrollable space and then remove it when I'm done – gtovar May 04 '17 at 20:30
  • 2
    this answer should be on top! – Kostanos Feb 26 '19 at 21:35
78

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.

SuppressWarnings
  • 3,855
  • 4
  • 22
  • 33
47

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>
Abhay Pratap
  • 1,267
  • 7
  • 13
  • 5
    Thanks! This is what I was looking for - android:fillViewport="true" is the key. – pratt Oct 07 '19 at 10:19
  • 1
    dont forget to add inside nestedscrollview, if you are using AppBarLayout `app:layout_behavior="@string/appbar_scrolling_view_behavior"` – majurageerthan Jan 16 '20 at 04:47
13

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.

StackAttack
  • 754
  • 7
  • 15
11

Just use constraint layout inside NestedScrollView or ScrollView.

<android.support.v4.widget.NestedScrollView
        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.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white">

 </android.support.constraint.ConstraintLayout>

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

thats it. enjoy your coding.

mahendren
  • 790
  • 8
  • 8
4

TO make a scrollable layout, the layout is correct. It will not be scrollable until there is reason to scroll(just like in any other layout). So add enough content and it will be scrollable, just like with any layout(Linear, Relative, etc). However, you cannot scroll properly in Blueprint or design-mode when designing with ConstraintLayout and ScrollView.

Meaning:

You can make a scrollable ConstraintLayout, but it will not scroll properly in the editor due to a bug/scenario that wasn't considered. But even though scrolling doesn't work in the editor, it works on devices. (I have made several scrolling COnstraintLayouts, so I have tested it)

Note

Regarding your code. The ScrollView is missing a closing tag, I don't know if it is the case in the file or if it is a copy-paste miss, but you may want to look at it.

Community
  • 1
  • 1
Zoe
  • 23,712
  • 16
  • 99
  • 132
  • 1
    To design a scrollable constraintlayout, in the current state of CL that is, you can expand the device's height and make it custom. Set the height of the layouts (ScrollView and CL) to a high number(e.g. 2000DP) and just do the normal designing. Note that you need a good computer to handle the expanding, as the really big custom devices demand a lot from the computer. It is a shame CL doesn't support designing with SCrollViews, but there are workarounds. such as expanding the device's height. – Zoe Mar 30 '17 at 13:24
3

For completing the previous answers I am adding the following example, which also takes into account the use of the AppBar. With this code, the Android Studio design editor seems to work fine with the ConstraintLayout.

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout
    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:fitsSystemWindows="true"
    android:background="@drawable/bg"
    android:orientation="vertical">

<android.support.design.widget.AppBarLayout
    android:id="@+id/app_bar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppTheme.ActionBar.AppOverlayTheme">
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

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

        <ImageView
            android:id="@+id/image_id"
            android:layout_width="match_parent"
            android:layout_height="@dimen/app_bar_height"
            android:fitsSystemWindows="true"
            android:scaleType="centerCrop"
            android:src="@drawable/intro"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="parent" />

        <TextView
            android:id="@+id/desc_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/text_margin"
            android:text="@string/intro_desc"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/image_id" />

        <Button
            android:id="@+id/button_scan"
            style="?android:textAppearanceSmall"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:backgroundTint="@color/colorAccent"
            android:padding="8dp"
            android:text="@string/intro_button_scan"
            android:textStyle="bold"
            app:layout_constraintTop_toBottomOf="@+id/desc_id" />

        <Button
            android:id="@+id/button_return"
            style="?android:textAppearanceSmall"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:layout_marginTop="8dp"
            android:backgroundTint="@color/colorAccent"
            android:padding="8dp"
            android:text="@string/intro_button_return"
            android:textStyle="bold"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/button_recycle" />

        <Button
            android:id="@+id/button_recycle"
            style="?android:textAppearanceSmall"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:backgroundTint="@color/colorAccent"
            android:padding="8dp"
            android:text="@string/intro_button_recycle"
            android:textStyle="bold"
            app:layout_constraintTop_toBottomOf="@+id/button_scan" />
    </android.support.constraint.ConstraintLayout>
</ScrollView>
</LinearLayout>
narko
  • 2,875
  • 1
  • 23
  • 27
3

Please use below solution it has taken my lots of time to fix.

Enjoy your time :)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    android:background="@color/white"
    >

    <ScrollView
        android:id="@+id/mainScroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:fillViewport="true"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentStart="true">
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">


            <android.support.constraint.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:layout_alignParentBottom="true"
                android:layout_alignParentEnd="true"
                >

            </android.support.constraint.ConstraintLayout>

        </RelativeLayout>
    </ScrollView>
</RelativeLayout>

Use Exactly like this u will definitely find your solution...

2

you need surrounded my constraint-layout with a ScrollView tag and gave it the property android:isScrollContainer="true".

Sam
  • 5,427
  • 7
  • 64
  • 78
2

Take out bottom button from the nestedscrollview and take linearlayout as parent. Add bottom and nestedscrollview as thier children. It will work absolutely fine. In manifest for the activity use this - this will raise the button when the keyboard is opened

android:windowSoftInputMode="adjustResize|stateVisible"

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical">

    <androidx.core.widget.NestedScrollView xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:fillViewport="true">

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

            <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/input_city_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="20dp"
                android:layout_marginTop="32dp"
                android:layout_marginEnd="20dp"
                android:hint="@string/city_name"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent">

                <com.google.android.material.textfield.TextInputEditText
                    android:id="@+id/city_name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:digits="abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                    android:lines="1"
                    android:maxLength="100"
                    android:textSize="16sp" />

            </com.google.android.material.textfield.TextInputLayout>

        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.core.widget.NestedScrollView>

    <Button
        android:id="@+id/submit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:onClick="onSubmit"
        android:padding="12dp"
        android:text="@string/string_continue"
        android:textColor="#FFFFFF"
        app:layout_constraintBottom_toBottomOf="parent" />

</LinearLayout>
Raghav Sharma
  • 734
  • 9
  • 17
1

There is a bug in version 2.2 that makes it impossible to scroll the ConstraintLayout. I guess it still exists. You can use LinearLayout or RelativeLayout alternatively.

Also, check out: Is it possible to put a constraint layout inside a ScrollView.

Peter
  • 134
  • 11
Ege Kuzubasioglu
  • 5,000
  • 10
  • 38
  • 76
1

Constraintlayout is the Default for a new app. I am "learning to Android" now and had a very hard time figuring out how to handle the default "sample" code to scroll when a keyboard is up. I have seen many apps where I have to close the keyboard to click "submit" button and sometimes it does not goes away. Using this [ScrollView / ContraintLayout / Fields] hierarchy it is working just fine now. This way we can have the benefits and ease of use from ConstraintLayout in a scrollable view.

1

A lot of answers here, nothing really simple. It's important that the ScrollView's lauout_height is set to match_parent while the layout_height of the ContraintLayout is wrap_content

<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

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

Quintin Balsdon
  • 4,546
  • 8
  • 45
  • 87
0

You can use HorizontalScrollView and it'll work as well!

Morgan Koh
  • 1,257
  • 19
  • 18
0

This is how I resolved it:
If you are using Nested ScrollView i.e. ScrollView within a ConstraintLayout then use the following configuration for the ScrollView instead of "WRAP_CONTENT" or "MATCH_PARENT":


<ScrollView
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintBottom_toTopOf="@+id/someOtherWidget"
    app:layout_constraintTop_toTopOf="parent">
Sajid2405
  • 159
  • 2
  • 7
0

in scrollview make height and width 0 add Top_toBottomOfand Bottom_toTopOf constraints that's it.

0

For me, none of the suggestions about removing bottom constraints nor setting scroll container to true seemed to work. What worked: expand the height of individual/nested views in my layout so they "spanned" beyond the parent by using the "Expand Vertically" option of the Constraint Layout Editor as shown below.

For any approach, it is important that the dotted preview lines extend vertically beyond the parent's top or bottom dimensions

Expand Vertically

kip2
  • 4,801
  • 3
  • 39
  • 59