Search code examples
androidandroid-layoutandroid-viewpagerandroid-nestedscrollview

Android NestedScrollView doesn't work in layout with viewpager


This is my layout: enter image description here

I want to be able to scroll upper parth of the layout (with name, image, textviews for followers/following...) when I scroll recyclerView in viewPager, so I read that I can use NestedScrollView to implement that, so I put NestedScrollView as my root layout:

NestedScrollView:
-----------------ConstraintLayout:
---------------------------------rest of the views as in picture above

I also added android:fillViewport="true" in NEstedScrollView because that solves a broblem of missing view pager. So the problem is that scroll view doesn't work, everything is same as before uting nestedScrollView , bottom part of my layout doesn't scroll of the screen while I scroll recyclerView. Doesn anyone know why, am I using nested scrollView wrong, I haven't found any example that can solve my problem and documentation is really bad. XML code for my layout:

<androidx.core.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:fillViewport="true">

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

        <androidx.appcompat.widget.Toolbar
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:background="?attr/colorPrimary"
                android:theme="?attr/actionBarTheme"
                android:minHeight="?attr/actionBarSize"
                android:elevation="4dp"
                android:id="@+id/title"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                tools:title="UserName"
                app:layout_constraintEnd_toEndOf="parent"/>

        <de.hdodenhof.circleimageview.CircleImageView
                android:id="@+id/profile_image"
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:layout_margin="8dp"
                app:srcCompat="@drawable/ic_profile_24dp"
                tools:src="@drawable/ic_profile_24dp"
                app:civ_border_color="@color/primaryLightColor"
                app:civ_border_width="1dp" android:layout_marginTop="8dp"
                app:layout_constraintTop_toBottomOf="@+id/title" android:layout_marginStart="8dp"
                app:layout_constraintStart_toStartOf="parent" android:layout_marginLeft="8dp"/>
        <TextView
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:id="@+id/textView"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginEnd="8dp" android:layout_marginRight="8dp"
                app:layout_constraintStart_toEndOf="@+id/profile_image" android:layout_marginLeft="8dp"
                android:layout_marginStart="8dp"
                app:layout_constraintBottom_toBottomOf="@+id/profile_image"
                app:layout_constraintTop_toTopOf="@+id/profile_image"
                tools:text="Short description "/>

        <TextView
                android:id="@+id/questions_label"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="@string/questions"
                android:layout_marginTop="8dp"
                app:layout_constraintTop_toBottomOf="@+id/profile_image" app:layout_constraintStart_toStartOf="parent"
                android:layout_marginLeft="8dp" android:layout_marginStart="8dp"
                app:layout_constraintHorizontal_bias="0.5" app:layout_constraintEnd_toStartOf="@+id/followers_label"/>
        <TextView
                android:id="@+id/questions_number"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18sp"
                android:textStyle="bold"
                tools:text="0"
                app:layout_constraintTop_toBottomOf="@+id/questions_label"
                app:layout_constraintEnd_toEndOf="@+id/questions_label"
                app:layout_constraintStart_toStartOf="@+id/questions_label"/>

        <TextView
                android:id="@+id/followers_label"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="@string/followers"
                android:layout_marginTop="8dp"
                app:layout_constraintTop_toBottomOf="@+id/profile_image"
                app:layout_constraintStart_toEndOf="@+id/questions_label" android:layout_marginStart="8dp"
                android:layout_marginLeft="8dp" android:layout_marginEnd="8dp"
                app:layout_constraintEnd_toStartOf="@+id/following_label" android:layout_marginRight="8dp"
                app:layout_constraintHorizontal_bias="0.5"/>

        <TextView
                android:id="@+id/following_label"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="@string/following"
                android:layout_marginTop="8dp"
                app:layout_constraintTop_toBottomOf="@+id/profile_image" android:layout_marginEnd="8dp"
                app:layout_constraintEnd_toEndOf="parent" android:layout_marginRight="8dp"
                app:layout_constraintStart_toEndOf="@+id/followers_label" app:layout_constraintHorizontal_bias="0.5"/>
        <TextView
                android:id="@+id/followers_number"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18sp"
                android:textStyle="bold"
                tools:text="0"
                app:layout_constraintEnd_toEndOf="@+id/followers_label"
                app:layout_constraintStart_toStartOf="@+id/followers_label"
                app:layout_constraintTop_toBottomOf="@+id/followers_label"/>
        <TextView
                android:id="@+id/following_number"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18sp"
                android:textStyle="bold"
                tools:text="0"
                app:layout_constraintEnd_toEndOf="@+id/following_label"
                app:layout_constraintStart_toStartOf="@+id/following_label"
                app:layout_constraintTop_toBottomOf="@+id/following_label"/>

        <com.google.android.material.tabs.TabLayout
                android:id="@+id/sliding_tabs"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:background="@color/primaryLightColor"
                app:tabMode="fixed" app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                android:layout_marginTop="8dp"
                app:layout_constraintTop_toBottomOf="@+id/followers_number"/>

        <androidx.viewpager.widget.ViewPager
                android:id="@+id/view_pager"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:background="@android:color/white"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/sliding_tabs" />

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

EDIT: code after suggestion:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
        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">

    <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="?attr/colorPrimary"
                android:theme="?attr/actionBarTheme"
                android:minHeight="?attr/actionBarSize"
                android:id="@+id/title"
                tools:title="UserName"/>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

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

            <de.hdodenhof.circleimageview.CircleImageView
                    android:id="@+id/profile_image"
                    android:layout_width="80dp"
                    android:layout_height="80dp"
                    android:layout_marginStart="@dimen/spacing_normal"
                    android:layout_marginLeft="@dimen/spacing_normal"
                    android:layout_marginTop="@dimen/spacing_normal"
                    app:civ_border_color="@color/secondaryDarkColor"
                    app:civ_border_width="1dp"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:srcCompat="@drawable/ic_profile_24dp"
                    tools:src="@drawable/ic_profile_24dp" />

            <com.google.android.material.textview.MaterialTextView
                    android:layout_width="0dp"
                    android:layout_height="0dp"
                    android:id="@+id/description"
                    android:layout_marginEnd="@dimen/spacing_normal"
                    android:layout_marginRight="@dimen/spacing_normal"
                    android:layout_marginLeft="@dimen/spacing_normal"
                    android:layout_marginStart="@dimen/spacing_normal"
                    app:layout_constraintStart_toEndOf="@+id/profile_image"
                    app:layout_constraintEnd_toEndOf="parent"                    app:layout_constraintBottom_toBottomOf="@+id/profile_image"
                    app:layout_constraintTop_toTopOf="@+id/profile_image"
                    tools:text="Short description "/>

            <include
                    layout="@layout/qff_layout"
                    android:id="@+id/qff_layout"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/spacing_small"
                    app:layout_constraintTop_toBottomOf="@+id/profile_image"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"/>

            <com.google.android.material.tabs.TabLayout
                    android:id="@+id/sliding_tabs"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:background="@color/primaryLightColor"
                    app:tabMode="fixed"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/qff_layout"/>

            <androidx.viewpager.widget.ViewPager
                    android:id="@+id/view_pager"
                    android:layout_width="0dp"
                    android:layout_height="0dp"
                    android:background="@android:color/white"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/sliding_tabs" />

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

What is wrong here, It doesn't make any sense, nothing scrolls except ViewPager


Solution

  • As you know NestedScrollView has one child and the height of his child must be wrap_content if you want scroll behavior for your layout.

    In your first layout, you must set the height of your ConstraintLayout to wrap_content but if you want your layout to be match_parent for whatever reason (such as you want to bound your ViewPager in the bottom of your layout) you must use suggested answer(it means you must use CoordinatorLayout) but with the following consideration:

    1- You should put all your stuff you want to scroll in the AppbarLayout.This layout extended from LinearLayout so you can easily put your stuff into it. from your question, I think you want to scroll all stuff above your ViewPager but you may change it as you want.

    (Note: actually, I recommend using CollapsingToolbar as a child of your AppbarLAyout and then put your stuff into it but for your question, this is work perfectly too)

    2- Add app:layout_scrollFlags="scroll" attribute in the root of your stuff within your AppbarLayout

    3- Add app:layout_behavior="@string/appbar_scrolling_view_behavior" attribute to the sibling of your AppbarLayout. In your question, you use this attribute in your NestedScrollView.

    This is my code:

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        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">
    
        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
    
            <androidx.appcompat.widget.Toolbar
                app:layout_scrollFlags="scroll"//I forget too add this, so I edit my answer
                android:id="@+id/title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="?attr/colorPrimary"
                android:minHeight="?attr/actionBarSize"
                android:theme="?attr/actionBarTheme" />
    
            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_scrollFlags="scroll"
                android:orientation="vertical">
    
                <View
                    android:id="@+id/profile_image"
                    android:layout_width="80dp"
                    android:layout_height="80dp"
                    android:layout_marginStart="10dp"
                    android:layout_marginLeft="10dp"
                    android:layout_marginTop="10dp"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
    
                <com.google.android.material.textview.MaterialTextView
                    android:id="@+id/description"
                    android:layout_width="0dp"
                    android:layout_height="0dp"
                    android:layout_marginStart="@dimen/spacing_normal"
                    android:layout_marginLeft="@dimen/spacing_normal"
                    android:layout_marginEnd="@dimen/spacing_normal"
                    android:layout_marginRight="@dimen/spacing_normal"
                    app:layout_constraintBottom_toBottomOf="@+id/profile_image"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toEndOf="@+id/profile_image"
                    app:layout_constraintTop_toTopOf="@+id/profile_image"
                    tools:text="Short description " />
    
                <include
                    layout="@layout/qff_layout"
                    android:id="@+id/qff_layout"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/profile_image" />
    
                <com.google.android.material.tabs.TabLayout
                    android:id="@+id/sliding_tabs"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:background="#559735"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/qff_layout"
                    app:tabMode="fixed" />
    
            </androidx.constraintlayout.widget.ConstraintLayout>
        </com.google.android.material.appbar.AppBarLayout>
    
        <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
            <androidx.viewpager.widget.ViewPager
                android:id="@+id/view_pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@android:color/white"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/sliding_tabs" />
        </androidx.core.widget.NestedScrollView>
    
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
    

    I didn't try this code but I'm pretty sure this is work for you :)