Search code examples
androidandroid-layoutscrollview

How to shrink a ScrollView's height keeping the other view(Button) fixed in place?


I have a ScrollView and a Button side by side in a vertical orientation(both children of ConstraintLayout's weighted chain with weight 1 and 0 respectively for ScrollView and the Button. BTW, you can optionally assume them to be children of a LinearLayout instead of a ConstraintLayout because a weighted ConstraintLayout chain works almost the same as a LinearLayout).

This is one of those typical use cases where you create the ScrollView with a list of certain items(children) and at the bottom have a big Button that searches your database based on the values filled in the ScollView children. Something like below:

enter image description here

The red-color encircled portion is where the Button is supposed to be(it is there but not visible).

Now the problem.

I want the button to be visible at all times irrespective of the ScrollView(if that implies shrinking of ScrollView's height, so be it because it is scrollable after all) but since the contents of ScrollView take enough space to hide the Button, by default it gets hidden. The solution(I think) would entail having to shrink the ScrollView's height just the amount that the Button is visible in the remaining space below.

Note that, I don't want the arrangement to end up like having the Button overlay the ScrollView's area. This is the case where no shrinkage of height would be required to ScrollView but rather the Button is made to float above it at the bottom, hiding some of its area. I want to force the ScrollView to adjust to the Button. Also, having weights of 1 and 0 respectively didn't help.

EDIT: Code for layout. (The Button is with id search_button)

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="8dp"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    >

    <ScrollView
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:id="@+id/scrollView2"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_constraintRight_creator="1"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintVertical_weight="1"
        app:layout_constraintBottom_toTopOf="@+id/search_button"
        app:layout_constraintVertical_chainStyle="spread_inside">

        <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="4dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp"
            android:layout_marginStart="4dp"
            android:layout_marginTop="8dp"
            android:background="@android:drawable/dialog_holo_light_frame"
            android:paddingEnd="8dp"
            android:paddingLeft="8dp"
            android:paddingRight="8dp"
            android:paddingStart="8dp"
            android:paddingTop="8dp">

            <LinearLayout
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                app:layout_constraintTop_toTopOf="parent"
                android:layout_marginTop="8dp"
                android:layout_marginLeft="8dp"
                android:layout_marginStart="8dp"
                app:layout_constraintLeft_toLeftOf="parent"
                android:layout_marginRight="8dp"
                android:layout_marginEnd="8dp"
                android:orientation="vertical"
                app:layout_constraintRight_toRightOf="parent"
                android:id="@+id/frameLayout">

                <include layout="@layout/layout_subject_search" />

            </LinearLayout>


            <View
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:background="?android:attr/listDivider"
                android:layout_marginLeft="8dp"
                app:layout_constraintLeft_toLeftOf="parent"
                android:layout_marginRight="8dp"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/frameLayout"
                android:layout_marginStart="8dp"
                android:layout_marginEnd="8dp"
                android:layout_marginTop="8dp"
                android:id="@+id/view" />

            <LinearLayout
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:layout_marginTop="8dp"
                android:layout_marginLeft="8dp"
                android:layout_marginStart="8dp"
                app:layout_constraintLeft_toLeftOf="parent"
                android:layout_marginRight="8dp"
                android:layout_marginEnd="8dp"
                android:orientation="vertical"
                app:layout_constraintRight_toRightOf="parent"
                android:id="@+id/frameLayout1"
                app:layout_constraintTop_toBottomOf="@+id/view">

                <include layout="@layout/layout_qualification_search" />

            </LinearLayout>

            <View
                android:layout_width="0dp"
                android:layout_height="2dp"
                android:background="?android:attr/listDivider"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                android:layout_marginTop="8dp"
                app:layout_constraintTop_toBottomOf="@+id/frameLayout1"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                android:layout_marginStart="8dp"
                android:layout_marginEnd="8dp"
                android:id="@+id/view2" />


            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/search_by_location_label"
                android:textSize="15sp"
                android:textStyle="bold"
                android:layout_marginLeft="8dp"
                app:layout_constraintLeft_toLeftOf="parent"
                android:layout_marginTop="8dp"
                app:layout_constraintTop_toBottomOf="@+id/view2"
                android:layout_marginStart="8dp" />

            <Switch
                android:id="@+id/location_toggle_switch"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_alignParentTop="true"
                android:text=""
                android:layout_marginTop="16dp"
                app:layout_constraintTop_toBottomOf="@+id/view2"
                android:layout_marginRight="16dp"
                app:layout_constraintRight_toRightOf="parent"
                android:layout_marginEnd="16dp" />

            <FrameLayout
                android:id="@+id/map_search_fragment"
                android:layout_width="0dp"
                android:layout_height="240dp"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_below="@+id/textView"
                android:layout_marginBottom="8dp"
                android:layout_marginEnd="8dp"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                android:layout_marginStart="8dp"
                android:layout_marginTop="8dp"
                android:background="@android:drawable/dialog_holo_light_frame"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/location_toggle_switch"
                app:layout_constraintVertical_bias="0.0">

            </FrameLayout>

        </android.support.constraint.ConstraintLayout>

    </ScrollView>

    <Button
        android:id="@+id/search_button"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="@string/search_tutors_string"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="4dp"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintVertical_weight="0"
        app:layout_constraintTop_toBottomOf="@+id/scrollView2" />

    <ProgressBar
        android:id="@+id/search_tutors_progress_bar"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:visibility="gone"/>


</android.support.constraint.ConstraintLayout>

EDIT 2: As asked by @marshmallow 's,

// include layout="@layout/layout_subject_search"

<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/search_by_subject_label"
        android:textStyle="bold"
        android:textSize="15sp"/>

    <com.learncity.learner.search.SubjectMultiAutoCompleteTextView
        android:id="@+id/subject_multi_auto_complete_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:completionThreshold="1"
        android:ems="10"/>

</merge>

// include layout="@layout/layout_qualification_search"

<merge xmlns:android="http://schemas.android.com/apk/res/android" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/search_by_qualification_label"
        android:textStyle="bold"
        android:textSize="15sp"/>

    <com.learncity.learner.search.QualificationMultiAutoCompleteTextView
        android:id="@+id/qualification_multi_auto_complete_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:completionThreshold="1"
        android:ems="10"/>


</merge>

Solution

  • First of all, thanks to @marshmallow for suggesting the wrap_content strategy as well as repeatedly testing and replying with updated solutions.


    The solution is bit of a twist on his suggestion:

    • Make layout_height for Button to be wrap_content. Why? We want to declare button's height as a reference for ScrollView to adjust its size and the true height of the button is obtained by using wrap_content.
    • Now, we want to tell the ScrollView to adjust its size as per button. To do this, we use layout_height as 0dp which translates to, "Use available constraints to adjust your size rather than asserting any fixed size of your own". For the same reason, Button's height is not 0dp.
    • Next, we establish a weighted chain relationship between the two with weight of 1 for ScrollView and 0 for Button(it doesn't effectively work for Button because width is not 0dp/match constraints; so just a pointer to ScrollView to take up space remaining other than Button)

    With this, the final solution becomes:(The solution tested for both portrait and landscape modes)

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="8dp"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        >
    
        <ScrollView
            android:id="@+id/scrollView2"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginBottom="4dp"
            app:layout_constraintBottom_toTopOf="@+id/search_button"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.0"
            app:layout_constraintVertical_chainStyle="spread_inside"
            app:layout_constraintVertical_weight="1"
            tools:layout_constraintLeft_creator="1"
            tools:layout_constraintRight_creator="1">
    
            <android.support.constraint.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginEnd="4dp"
                android:layout_marginLeft="4dp"
                android:layout_marginRight="4dp"
                android:layout_marginStart="4dp"
                android:layout_marginTop="8dp"
                android:layout_marginBottom="8dp"
                android:background="@android:drawable/dialog_holo_light_frame"
                android:paddingEnd="8dp"
                android:paddingLeft="8dp"
                android:paddingRight="8dp"
                android:paddingStart="8dp"
                android:paddingTop="8dp">
    
                <LinearLayout
                    android:id="@+id/frameLayout"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:orientation="vertical"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toTopOf="parent">
    
                    <include layout="@layout/layout_subject_search" />
    
                </LinearLayout>
    
    
                <View
                    android:id="@+id/view"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:background="?android:attr/listDivider"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/frameLayout" />
    
                <LinearLayout
                    android:id="@+id/frameLayout1"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:orientation="vertical"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/view">
    
                    <include layout="@layout/layout_qualification_search" />
    
                </LinearLayout>
    
                <View
                    android:id="@+id/view2"
                    android:layout_width="0dp"
                    android:layout_height="2dp"
                    android:layout_marginEnd="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:background="?android:attr/listDivider"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/frameLayout1" />
    
    
                <TextView
                    android:id="@+id/textView"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="8dp"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:text="@string/search_by_location_label"
                    android:textSize="15sp"
                    android:textStyle="bold"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/view2" />
    
                <Switch
                    android:id="@+id/location_toggle_switch"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentEnd="true"
                    android:layout_alignParentRight="true"
                    android:layout_alignParentTop="true"
                    android:layout_marginEnd="16dp"
                    android:layout_marginRight="16dp"
                    android:layout_marginTop="16dp"
                    android:text=""
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/view2" />
    
                <FrameLayout
                    android:id="@+id/map_search_fragment"
                    android:layout_width="0dp"
                    android:layout_height="240dp"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentStart="true"
                    android:layout_below="@+id/textView"
                    android:layout_marginBottom="8dp"
                    android:layout_marginEnd="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:background="@android:drawable/dialog_holo_light_frame"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintHorizontal_bias="0.0"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/location_toggle_switch"
                    app:layout_constraintVertical_bias="0.0">
    
                </FrameLayout>
    
            </android.support.constraint.ConstraintLayout>
    
        </ScrollView>
    
        <Button
            android:id="@+id/search_button"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="4dp"
            android:layout_marginTop="4dp"
            android:text="@string/search_tutors_string"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/scrollView2"
            app:layout_constraintVertical_weight="0" />
    
        <ProgressBar
            android:id="@+id/search_tutors_progress_bar"
            style="?android:attr/progressBarStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:visibility="gone"/>
    
    
    </android.support.constraint.ConstraintLayout>