17

Update:

  • Actual issue is with CoordinatorLayout not with RecycleView.
  • Instead of using RecycleView I tried TextView inside ScrollView and it is the same issue.
  • Something is not aligned if you have Toolbar as ActionBar and using CoordinatorLayout with another ToolBar as Sticky Header with scrolling element at bottom

Original:

I'm in process of develop a view which needed Sticky header implementation with recycle view at bottom. I have used Coordinator layout support as describe here.

What is working:

  • Sticky View on scroll list.
    • Toolbar using layout_collapseMode = pin & CollapsingToolbarLayout using layout_scrollFlags = scroll|exitUntilCollapsed|snap property.
    • Recycle view with behaviour app:layout_behavior="@string/appbar_scrolling_view_behavior"

What is issue:

  • Recycle view leaving margin at bottom, it has same size as Toolbar I'm using to sticky view.
  • Recycle view last item does not display, it need extra bottom_margin as size of sticky tool bar view.

Observation:

  • If I fill recycle instant then it work. But if notify it with some delay then it causing issue.
  • Update. In another trial and run**, instead of using Recycle I put an TextView inside the NestedScrollView.(PFA) (not updated in layout here)
    • Here I have added text from xml and after delay of 2 second just append some more text and it's same result.
    • It's layout that take bottom margin again. So nothing specific related to Recycle view, it seems some issue with CoordinatorLayout.

I have tried with multiple solution available here, here, but none of working.

PFA, current output.

enter image description here

Update PFA, experiment with text view with delay.

enter image description here

Here is the layout file.

<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:id="@+id/summaryAppBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/main.collapsing"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="256dp"
                android:background="@drawable/fable_1"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.3" />

            <!-- This is sticky header-->
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/summaryToolBar"
                android:layout_width="match_parent"
                android:layout_height="72dp"
                android:layout_gravity="center"
                android:background="@android:color/white"
                android:padding="@dimen/common_layout_margin"
                android:visibility="visible"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

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

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textSize="24sp"
                        android:text="Name" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="right"
                        android:textSize="24sp"
                        android:text="Offer"/>

                </FrameLayout>

            </androidx.appcompat.widget.Toolbar>

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

   <!-- Bottom margin if I do't use then it does not display last child item. Wired but true in this case-->

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:visibility="visible"
        android:layout_marginBottom="72dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:listItem="@layout/item_dessert" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
Pradip Tilala
  • 1,715
  • 16
  • 24
CoDe
  • 11,056
  • 14
  • 90
  • 197
  • please share your code – begiNNer Mar 01 '19 at 07:51
  • had you added : android:fitsSystemWindows="true" to your coordinator view? – Deep Patel Mar 01 '19 at 09:15
  • yes, but that pushing layout up and resulting action bar cut from top. – CoDe Mar 01 '19 at 09:20
  • 3
    Don't you have `android:layout_marginBottom="72dp"` set? – P Fuster Mar 01 '19 at 09:33
  • @PFuster so I added issue in What is issue section. Removing of that even not fixing bottom space issue. Please also refer **Observation** section, that's where I could be able to conclude so far. – CoDe Mar 03 '19 at 00:10
  • @CoDe: Did you find a solution for this issue? I also have an ugly white bar appearing at the bottom of my RecyclerView when I'm scrolling upwards. It makes my NavBar intransparent. "clipToPadding=false" has no effect. See here the video: https://github.com/patrickfrei/test_coding/blob/main/issue.webm – Patrick Jan 01 '22 at 23:15

5 Answers5

6

I believe that the CoordinatorLayout (maybe the AppBarLayout or CollapsingToolbarLayout - not sure which component) is recording the incorrect height of the CollapsingToolbarLayout due to the sticky toolbar. The behavior differs if items are added before or after the initial layout.

Try the following:

  1. Remove android:layout_marginBottom="72dp" from the XML for the RecyclerView.
  2. Add android:minHeight="72dp" to the XML for CollapsingToolbarLayout

Since your sticky toolbar is set at 72dp, it is OK to use minHeight set to 72dp.

If you have trouble with this, post back here.


Here is a quick demo of your layout using a NestedScrollView and the changes mentioned above.

Update: I have worked this out using RecyclerView which displays the same problem. Demo project showing the problem and the fix is on GitHub.

enter image description here

Here is the code:

MainActivity.java

public class MainActivity extends AppCompatActivity {  
    // Set to true to break the layout; false for it to work.  
    // The setting of this flag should only matter for the 
    // layout activity_not_working.  
    private boolean mBreakIt = true;  

    //    private int mLayoutToUse = R.layout.activity_not_working;  
    private int mLayoutToUse = R.layout.activity_working;  

    private LinearLayout mLayout;  

    @Override  
  protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(mLayoutToUse);  

        mLayout = findViewById(R.id.linearLayout);  
        if (mBreakIt) {  
            mLayout.post(new Runnable() {  
                @Override  
  public void run() {  
                    addViews();  
                }  
            });  
        } else {  
            addViews();  
        }  
    }  

    private void addViews() {  
        for (int i = 0; i < 50; i++) {  
            TextView tv = new TextView(MainActivity.this);  
            tv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,  
                    ViewGroup.LayoutParams.WRAP_CONTENT));  
            tv.setText("TextView #" + (i + 1));  
            mLayout.addView(tv);  
        }  
    }  
}

activity_working.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/summaryAppBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/main.collapsing"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="72dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="256dp"
                android:background="@drawable/beach"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.3" />

            <!-- This is sticky header-->
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/summaryToolBar"
                android:layout_width="match_parent"
                android:layout_height="72dp"
                android:layout_gravity="center"
                android:background="@android:color/white"
                android:padding="@dimen/common_layout_margin"
                android:visibility="visible"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

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

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Name"
                        android:textSize="24sp" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="right"
                        android:text="Offer"
                        android:textSize="24sp" />

                </FrameLayout>

            </androidx.appcompat.widget.Toolbar>

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <!-- Bottom margin if I do't use then it does not display last child item. Wired but true in this case-->
    <!-- Removed following: -->
    <!--android:layout_marginBottom="72dp"-->

    <androidx.core.widget.NestedScrollView
        android:id="@+id/nestedScrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_blue_light"
        android:visibility="visible"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        app:layout_insetEdge="bottom"
        tools:listItem="@layout/item_dessert">

        <LinearLayout
            android:id="@+id/linearLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="A TextView" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="A TextView" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="A TextView" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="A TextView" />


        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

activity_not_working.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/summaryAppBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/main.collapsing"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="256dp"
                android:background="@drawable/beach"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.3" />

            <!-- This is sticky header-->
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/summaryToolBar"
                android:layout_width="match_parent"
                android:layout_height="72dp"
                android:layout_gravity="center"
                android:background="@android:color/white"
                android:padding="@dimen/common_layout_margin"
                android:visibility="visible"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

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

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Name"
                        android:textSize="24sp" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="right"
                        android:text="Offer"
                        android:textSize="24sp" />

                </FrameLayout>

            </androidx.appcompat.widget.Toolbar>

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <!-- Bottom margin if I do't use then it does not display last child item. Wired but true in this case-->
    <!-- Removed following: -->
    <!--android:layout_marginBottom="72dp"-->

    <androidx.core.widget.NestedScrollView
        android:id="@+id/nestedScrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="72dp"
        android:background="@android:color/holo_blue_light"
        android:visibility="visible"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        app:layout_insetEdge="bottom"
        tools:listItem="@layout/item_dessert">

        <LinearLayout
            android:id="@+id/linearLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="A TextView" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="A TextView" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="A TextView" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="A TextView" />


        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
Cheticamp
  • 61,413
  • 10
  • 78
  • 131
  • I tried this but in my case it is same issue. Please note I already have toolbar set as an Action Bar. I'm still on it and will update soon. – CoDe Mar 13 '19 at 10:32
5

Can you please try the below layout file. I have tested it and it works fine. You can remove the marginButtom from the recyclerview as well.

xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">


<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:id="@+id/summaryAppBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.google.android.material.appbar.CollapsingToolbarLayout
        android:id="@+id/main.collapsing"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="256dp"
            android:background="@drawable/fable_1"
            app:layout_collapseMode="parallax"
            app:layout_collapseParallaxMultiplier="0.3" />

        <!-- This is sticky header-->
        <androidx.appcompat.widget.Toolbar
            android:id="@+id/summaryToolBar"
            android:layout_width="match_parent"
            android:layout_height="72dp"
            android:layout_gravity="center"
            android:background="@android:color/white"
            android:padding="@dimen/common_layout_margin"
            android:visibility="visible"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

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

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="24sp"
                    android:text="Name" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="right"
                    android:textSize="24sp"
                    android:text="Offer"/>

            </FrameLayout>

        </androidx.appcompat.widget.Toolbar>

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>



    <androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:visibility="visible"
    android:layout_marginBottom="72dp"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:listItem="@layout/item_dessert" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>
Jiten Basnet
  • 1,623
  • 15
  • 31
4

The RecyclerView height is just being calculated wrongfully, when entering scroll. these two different examples only added confusion to the question, without the least Java code provided.

simply remove this one line from the RecyclerView:

android:layout_marginBottom="72dp"

this attribute has little use, because it's the default value:

android:visibility="visible"

don't set the RecyclerView height like this:

android:layout_height="match_parent"

but make it fill up the available space:

android:layout_height="0dp"
android:layout_weight="1.00"

so that the RecyclerView would always fit, in case there is a toolbar present, whether or not - this toolbar just shouldn't be set sticky, because this is what demands halfheartedly "fixing" the layout. a BottomNavigationView might eventually be useful there, depending on what that toolbar, might be good for. even found the source of the script: CoordinatorBehaviorExample, which should have been attributed, as the license requires it.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • Hi Martin, I have added comment in layout section. About weight property, it will not be possible as direct child of **CoordinatorLayout**, though putting NestedScrollView and take RecycleView inside LinearLayout also not making any difference. – CoDe Mar 02 '19 at 23:53
  • Toolbar I'm using as an part of Sticky header, in GIF I have shown with text (Name & Offer label). About BottomNavigationView, not really sure how this can fix it !! – CoDe Mar 02 '19 at 23:56
3

I assume there could be issue while adding new data and notify adapter.

You should change from notifyDataSetChanged() to notifyItemInserted(index).

More documentation on notifyItemInserted(index) here.

Hope it helps.

Hiren Patel
  • 52,124
  • 21
  • 173
  • 151
  • Hiren, this help to fix issue till some extend but original issue still persist. Please refer updated post. – CoDe Mar 03 '19 at 01:43
3

Hey you have set a marginBottom attribute there. Remove that. That's where the error is. The code for the RecyclerView should be:

<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:listItem="@layout/item_dessert" />
Gourav
  • 2,746
  • 5
  • 28
  • 45
  • Hi Gourav, it is needed for some weird unknown reason, issue I have added in **What is issue section** and in layout section comment as well. Please refer. – CoDe Mar 02 '19 at 23:58
  • 1
    android:clipToPadding="false" is what I was looking for... +1 – jwitt98 Dec 23 '19 at 03:20