61

With creation of NestedScrollView you can put scrolling view inside another scrolling view as long as those implement NestedScrollingChild and NestedScrollingParent correctly.

(This is not bad design pattern "Ian Lake (from Google) actually recommends putting a RecyclerView inside a nestedscrollview here: plus.google.com/u/0/+AndroidDevelopers/posts/9kZ3SsXdT2T")

I want to put RecyclerView inside NestedScrollView and fortunately RecyclerView implements NestedScrollingChild so you can put it inside NestedScrollView.

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild

I have read these posts:

How to use RecyclerView inside NestedScrollView?

NestedScrolling with NestedScrollView, RecyclerView (Horizontal), inside a CoordinatorLayout

But the problem with most voted solution is, it calls all of the items of RecyclerView so for example if it is an endless RecyclerView and when the user reaches the end of the list you want to make a network request then with that solution the RecyclerView calls server repeatedly because it automatically reaches the last item of RecyclerView.

Anyway, how to set parameter so I can put RecyclerView inside NestedScrollView.(actually I want to put a viewgroup like framelayout or relativelayout as a single childe of nestedscrollview and then I want to put recyclerview inside framelayout or relativelayout)

When I put RecyclerView inside NestedScrollView there is nothing to display.


In order to create a sample project you can use cheesesquare and change the CheeseDetailActivity to have a RecyclerView.


Although the answer of BNK is not correct but BNK has tried a lot. So I award him the bounty. Still looking for nice solution....

Community
  • 1
  • 1
mmlooloo
  • 18,937
  • 5
  • 45
  • 64
  • 1
    RecyclerView calls server repeatedly because it automatically reaches the last item of RecyclerView.. Are you sure about this ? – Ramesh Nov 02 '15 at 06:37
  • 1
    @Ramesh yes with suggested solution it calls the last visible item which is the last item of current data. it is not the real last visible item. – mmlooloo Nov 02 '15 at 09:31
  • try this [link](http://androhub.com/android-toolbar-animation-using-design-support-library/). – Surender Kumar Nov 03 '15 at 08:05
  • @SurenderKumar thanks but read my question. that is not the answer i am looking for – mmlooloo Nov 03 '15 at 08:07
  • If you want to put it in nested scrollview then you have to define the height of recycler view. – Surender Kumar Nov 03 '15 at 08:08
  • the height must be wrap_content. – mmlooloo Nov 03 '15 at 08:09
  • Have you tried removing `FrameLayout` around `RecyclerView`? I assume that `NestedScrollView` checks the type of its direct child, but does not dive deeper than that. So, it has no way to discover that `RecyclerView` in fact implements Nested interface – Dmitry Zaytsev Nov 03 '15 at 08:28
  • @mmlooloo have you fixed the problem I am facing the scrolling is very laggy I have Imageview and `heterogenic layout` for row and also data is not populated properly. If I used only RecyclerView then it is working fine – Kaushik Nov 04 '15 at 12:33
  • @Kaushik no unfortunatly – mmlooloo Nov 04 '15 at 13:12
  • 1
    Any news on this? I am facing the same problem too... frustrating – dgngulcan Jul 15 '16 at 11:30
  • @mmlooloo just checked latest recyclerview version; 25.0.0; the issue still exists, did you find any workarounds? – Rez Oct 28 '16 at 19:15
  • @EBLiS try andre719mv solution, it may work. I have not try it yet but some people said it is working. – mmlooloo Oct 29 '16 at 07:33
  • 1
    @mmlooloo nope! non of the answers worked! I ended up with a recyclerview and a vertical linear layout manager, and replacing inner recyclerview with custom rows, for example four items in a row!! – Rez Oct 31 '16 at 10:54
  • @MohammadReza did using different viewtypes in recyclerview solve the not recycling issue? – hushed_voice Dec 04 '19 at 13:28

4 Answers4

38

The following is my new updated answer:

<android.support.v4.widget.NestedScrollView
        android:id="@+id/scrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

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

            <android.support.v7.widget.CardView
                android:id="@+id/cardview1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/card_margin">

                <LinearLayout
                    style="@style/Widget.CardContent"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="Info CardView1"
                        android:textAppearance="@style/TextAppearance.AppCompat.Title" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="@string/cheese_ipsum" />

                </LinearLayout>

            </android.support.v7.widget.CardView>

            <android.support.v7.widget.CardView
                android:id="@+id/cardview2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/cardview1"
                android:layout_margin="@dimen/card_margin">

                <LinearLayout
                    style="@style/Widget.CardContent"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="Info CardView2"
                        android:textAppearance="@style/TextAppearance.AppCompat.Title" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="@string/cheese_ipsum" />

                </LinearLayout>

            </android.support.v7.widget.CardView>

            <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerview"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/cardview2"
                android:clipToPadding="false"
                android:paddingTop="0dp"/>

        </RelativeLayout>

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

In Activity:

        RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(true); // true: with header
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);            
        final MyLinearLayoutManager layoutManager = new MyLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false, getScreenHeight(this));
        // final CustomLinearLayoutManager layoutManager = new CustomLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(recyclerViewAdapter);  
        // recyclerView.setNestedScrollingEnabled(false); // Disables scrolling for RecyclerView, however, CustomLinearLayoutManager used instead of MyLinearLayoutManager

I have also updated to My GitHub's sample project

Screenshot:

enter image description here


BNK
  • 23,994
  • 8
  • 77
  • 87
  • 2
    thanks but adding `android:fillViewport="true"` without adding framelayout dose not work. thanks again – mmlooloo Nov 03 '15 at 09:03
  • Don't you want framelayout? Why not? – BNK Nov 03 '15 at 09:05
  • because adds depth in hierarchy views and also NestedScrollView is a vewgroup – mmlooloo Nov 03 '15 at 09:06
  • I updated my answer, remove 2 lines `rv.setHasFixedSize(false); rv.setNestedScrollingEnabled(false);`, I check it works – BNK Nov 03 '15 at 09:18
  • actually your answer idea is the same as Simon, adding framelayout. if you can do without that then your answer will be the standard solution. – mmlooloo Nov 03 '15 at 09:22
  • I have just replaced `FrameLayout` by `RelativeLayout`, it still works, ofcourse with `android:fillViewport="true"` :) – BNK Nov 03 '15 at 09:26
  • I know adding another viewgroup will work, you can add linearlayout and it will work. BUT it must work without any extra viewgroups. Because NestedScrollView itself is vewgroup. So standard solution must not add new viewgroups. – mmlooloo Nov 03 '15 at 09:30
  • I will try it tomorrow :) – BNK Nov 03 '15 at 09:31
  • if you want the bounty try in 24+5 hrs. – mmlooloo Nov 03 '15 at 09:33
  • Don't worry about the bounty, you can give it to Simon now. Actually, I have not read his answer yet, I only read the 2 links you provided. More important, I just want to have more knowledge about layouts :D. Now I on mobile so cannot test anymore, must wait until tomorrow :) – BNK Nov 03 '15 at 09:38
  • Regarding your comment "Because NestedScrollView itself is vewgroup. So standard solution must not add new viewgroups", how about standard ScrollView, inside it also another layout (Relative, Linear...) – BNK Nov 03 '15 at 09:51
  • ScrollView dose not implement NestedScrollingChild and NestedScrollingParent – mmlooloo Nov 03 '15 at 09:54
  • So, you can try remove framelayout, then use setMinimumHeight() for recylerview to see if it work – BNK Nov 03 '15 at 10:01
  • thats ugly solution, the height must be wrap_content. – mmlooloo Nov 03 '15 at 10:05
  • Pls look at my updated answer (full content of activity_detail.xml). I uploaded the customized project to https://github.com/ngocchung/cheesesquare-master – BNK Nov 04 '15 at 01:06
  • if I add recyclerview below of last cardView it dose not show. can you fix it? this is the main problem now. – mmlooloo Nov 04 '15 at 03:15
  • Last cardView? Where is it? Is it your new requirement? In your question and your above comments, I only see your requirement is "recyclerview direct inside nestedscrollview without any framelayout, relativelayout..." and I have a working solution already – BNK Nov 04 '15 at 03:18
  • It is not a new requirement, I add recyclerView below the last card of cheessquer. if you answer `How to put RecycelerView inside NestedScrollView?` so it must work. dose not it? – mmlooloo Nov 04 '15 at 03:24
  • No, I just cloned the cheesesquare project in your question and customized its CheeseDetailActivity, I don't care MainActivity – BNK Nov 04 '15 at 03:27
  • in CheeseDetailActivity there are some cardViews. it is in your `activity_detail_bk` layout. I have not changed anything and also have not added any new requirement. – mmlooloo Nov 04 '15 at 03:29
  • I see your idea now, however, why do you want to keep those cardviews? You can move them into recyclerview instead – BNK Nov 04 '15 at 03:33
  • because in my main project I have to add a lot of widget and at the end I have to add recyclerview. adding those widget inside recyclerview and using view type really complex my design. – mmlooloo Nov 04 '15 at 03:36
  • One more thing, if you keep those cardviews, you must put recyclerview inside LinearLayout because NestedScrollview can have only 1 direct child, but in your comments, you don't want any layout – BNK Nov 04 '15 at 03:36
  • yes I have to, but please make sure the recyclerview height is not fix, it must expand normally and as you scroll it fills the entire screen. not fix at the bottom of the page. – mmlooloo Nov 04 '15 at 03:50
  • Pls take a look. Regariding to `not fix at the bottom of the page` I think you have to use code (looks like child scrollview inside parent scrollview) – BNK Nov 04 '15 at 03:53
  • "I think you have to use code (looks like child scrollview inside parent scrollview)" what do you mean? – mmlooloo Nov 04 '15 at 04:03
  • I don't think a way using layout file for your requirement `not fix at the bottom of the page`, so I think you must use code more – BNK Nov 04 '15 at 04:05
  • I have just found a nicer solution, please go to my github to get updated code :) – BNK Nov 04 '15 at 06:11
  • Pls look at my updated answer, it works nicely, you can add recyclerview between cardviews too – BNK Nov 04 '15 at 06:28
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/94161/discussion-between-mmlooloo-and-bnk). – mmlooloo Nov 04 '15 at 07:28
  • Sorry, I cannot chat now – BNK Nov 04 '15 at 07:29
  • I am sure that new updated code meets your requirements `make sure the recyclerview height is not fix, it must expand normally and as you scroll it fills the entire screen. not fix at the bottom of the page`, see you later :) – BNK Nov 04 '15 at 07:32
  • Calls the server? I don't undertand your idea? You get the data from the server in your project? – BNK Nov 04 '15 at 07:36
  • Read my question carefully – mmlooloo Nov 04 '15 at 07:37
  • Hey! I don't know why you must and how did you make server request at the end of the list, however, read my following link http://stackoverflow.com/questions/32492011/how-to-load-datajson-into-recycler-view-using-volley/32492513#32492513, I often use that way to get data from server into recyclerview, I think it does not request over and over as you think – BNK Nov 04 '15 at 07:43
  • Your solution dose not satisfy pagination REST API. – mmlooloo Nov 04 '15 at 07:50
  • If you're sure about "over and over" requests, post your code or your github's sample project and logcat information that displayed that thing – BNK Nov 04 '15 at 07:51
  • logcat the `findLastVisibleItemPosition()` method of LayoutManager . if your list has 50 items and just 5 items are visible that method should not return 50. – mmlooloo Nov 04 '15 at 07:54
  • Log where? If inside activity, `Log.i("LOG",String.valueOf(myLinearLayoutManager.findLastVisibleItemPosition()));` output -1 – BNK Nov 04 '15 at 08:00
  • inside recyclerView.addOnScrollListener – mmlooloo Nov 04 '15 at 08:29
  • I have tried, it is 0 first, then when scrolling, addOnScrollListener not called anymore. If add it inside setOnScrollChangeListener of nestedScrollView, it always 0 too – BNK Nov 04 '15 at 08:37
  • But mine is called, just google it, I think you have made a mistake somewhere. – mmlooloo Nov 04 '15 at 08:41
  • Wrong called, now right method: `11-04 15:43:26.216 3090-3090/com.support.android.designlibdemo I/visibleItemCount: 150 11-04 15:43:26.216 3090-3090/com.support.android.designlibdemo I/totalItemCount: 150 11-04 15:43:26.216 3090-3090/com.support.android.designlibdemo I/pastVisiblesItems: 149` – BNK Nov 04 '15 at 08:43
  • pastVisiblesItems is String.valueOf(layoutManager.findLastVisibleItemPosition()). Must log inside `setOnScrollChangeListener` of ScrollView – BNK Nov 04 '15 at 08:44
  • So now I think you touch the problem:-) now If you can find a solution. – mmlooloo Nov 04 '15 at 08:45
  • visibleItemCount: 150 == totalItemCount: 150 – mmlooloo Nov 04 '15 at 08:46
  • `visibleItemCount = layoutManager.getChildCount(); totalItemCount = layoutManager.getItemCount(); pastVisiblesItems = layoutManager.findLastVisibleItemPosition();` – BNK Nov 04 '15 at 08:46
  • Sorry, actually, I still cannot understand your idea `over and over request`. If you don't mind, please post your code or your github sample project that having this issue so that I can check more – BNK Nov 04 '15 at 08:48
  • Sorry, I cannot chat. What a pity my answer cannot work completely for all your requirements. Actually I have not ever tried pagination Rest API before, however, with your current question, I have more knowlegde about the new layouts of Android, thanks anyway, see you later :) – BNK Nov 04 '15 at 08:54
  • What is the value of `mVisibleThreshold`? Do you mean `End has been reached` always reached? – BNK Nov 04 '15 at 09:08
  • and also I wonder why you can add a lot of comment but can not chat on stackoverflow. I think you misunderstand the chat on this site. just press the link it is as if you are commenting – mmlooloo Nov 04 '15 at 09:08
  • if you press the link ` automatically move this discussion to chat?` when you are going to add new comment we can chat by typing like here. – mmlooloo Nov 04 '15 at 09:09
  • when you press `add comments` and the dialog is opened to write there is a link above that dialog. try it – mmlooloo Nov 04 '15 at 09:12
  • I have posted in chat windows, don't you see it? – BNK Nov 04 '15 at 09:18
  • Hi! Please go to my new sample project https://github.com/ngocchung/NestedScrollView, I use a little trick with screenheight. Please take a look, although it is not 100% as nice as you want, however, the last item will not be reached automatically. Hope this helps :) – BNK Nov 05 '15 at 08:31
  • 1
    Thank you, right now I have to fix some other part of my main project, when I reach that UI I will surely try your new sample. I have understand your trick, it seems work nicely. again thanks. – mmlooloo Nov 05 '15 at 08:40
  • Hello! Long time no see :) Have you reached that UI and have you tried my sample yet? – BNK Nov 14 '15 at 14:38
  • No I finally used recyclerview with multi view type holder. – mmlooloo Nov 14 '15 at 14:42
  • Uhm, sound better, then you don't need nestedscrollview anymore, right? – BNK Nov 14 '15 at 22:36
  • Suppose all I want to add is a header to the RecyclerView (jst as done for ListeView). Is it possible by using a NestedScrollView ? – android developer Nov 16 '15 at 22:37
  • @androiddeveloper: do you mean like this one http://robusttechhouse.com/tutorial-how-to-add-header-to-recyclerview-in-android/ ? – BNK Nov 17 '15 at 02:06
  • @BNK Yes, but without changing the adapter. For the adapter solution, I've already found how to do it, and wrote about it, here : http://stackoverflow.com/a/33746292/878126 . The adapter solution also has a disadvantage that the adapter needs to manage the header, so I can't just call "setVisibility" on the header view (because it leaves an empty, unused space for some reason). – android developer Nov 17 '15 at 08:35
  • @androiddeveloper: IMO, if recyclerview is the only one inside nestedscrollview, why don't we put it inside linearlayout instead, don't need nestedscrollview anymore. Then, use another textview/cardview as the header. **Commonware** has had the same idea at http://stackoverflow.com/questions/30873176/recylerview-with-a-fixed-first-row-as-header, pls take a look. – BNK Nov 17 '15 at 08:41
  • @BNK Well, if the LinearLayout is the parent, how would the header be scrolled, so that if it's too large, the user could scroll and show the rest of the header ? – android developer Nov 17 '15 at 08:44
  • @androiddeveloper The header is often sticky/fixed postion, I think :) – BNK Nov 17 '15 at 08:46
  • @BNK wouldn't it be weird to have a header that takes space, so that your recyclerView take less space? I guess it depends on the requirements... – android developer Nov 17 '15 at 09:06
  • @androiddeveloper: so, you can try replacing header view by an empty view instead of setVisibility(View.GONE) – BNK Nov 17 '15 at 09:36
  • @BNK I don't think it will work.I've decided to add a boolean in the adapter to show/hide the header, instead, and it worked. – android developer Nov 18 '15 at 00:35
  • @androiddeveloper I just updated my sample project at GitHub that also uses boolean variable, please take a look if it is the same as yours https://github.com/ngocchung/NestedScrollView – BNK Nov 18 '15 at 07:58
  • @BNK Wait, so you succeeded using a nestedScrollView , in order to have a header for the recyclerView ? If so, please put your answer here: http://stackoverflow.com/q/33729642/878126 – android developer Nov 18 '15 at 08:50
  • @androiddeveloper: you can download my sample code, I have read your question before, however I don't understand much, and haven't ever tried `StaggeredGridLayoutManager` so cannot post an answer :) – BNK Nov 18 '15 at 08:53
  • @BNK Using StaggeredGridLayoutManager was just for checking out if it's a possible solution, but then I've found I can use spanning on the GridLayoutManager, and updated the question. The sample works, but it allows me to scroll on the recyclerView without having the header being scrolled together with it. Probably because of the NestedScrollView – android developer Nov 18 '15 at 08:55
  • @androiddeveloper: you can try scrolling again, the header scrolled, as my screenshot in GitHub – BNK Nov 18 '15 at 08:56
  • @BNK It still allows to scroll the recyclerView yet the header doesn't get scrolled. Try to scroll to the top, and then start touching the recyclerView and scroll there. The header gets fixed in its location, while the recyclerView gets scrolled. – android developer Nov 18 '15 at 12:51
  • @androiddeveloper: pls see the screenshots https://drive.google.com/file/d/0B2HGUM4c0YwpR3VXakVNSDc0Y1E/view?usp=sharing and https://drive.google.com/file/d/0B2HGUM4c0YwpUzFWQUxKcV9UR0k/view?usp=sharing – BNK Nov 19 '15 at 01:31
  • @BNK As I wrote, it doesn't work well. Here's a video : https://files.fm/g/ndlbwvk#aa/device-2015-11-20-012911.mp4 – android developer Nov 19 '15 at 23:33
  • @androiddeveloper if you don't want the RV to be scrolled inside NSV as in the video,simply call recyclerView.setNestedScrollingEnabled(false);, however, then RV will not display all child items when using `MyLinearLayoutManager`, `CustomLinearLayoutManager` should be used instead – BNK Nov 20 '15 at 06:23
  • @BNK So a NestedScrollView is not a good solution as I thought. OK. – android developer Nov 20 '15 at 10:12
  • hi....great solution....but i want to use grid layout of recyclerview...how can i? – H Raval Dec 21 '15 at 07:46
  • @HRaval sorry, I have not ever tried it before, IMO, you can read http://stackoverflow.com/questions/27744788/changing-number-of-columns-in-recyclerview-gridlayout and http://stackoverflow.com/questions/26566954/recyclerview-gridlayoutmanager-set-square-dimensions or search more in S.O – BNK Dec 21 '15 at 07:50
  • 1
    Hi guys! Super interesting conversation! I was checking out @BNK's project (https://github.com/ngocchung/NestedScrollView) and started playing with it a little bit, since I needed to do something similar. I have one question though, when the content ABOVE the recyclerview (CardViews) fit in the screen without the need of scrolling down, the content gets scrolled down automatically to the start of the Recyclerview. You can test this by removing or commenting one of the CardViews at the top of `content_main.xml`. Is there a workaround for this behaviour? Ideally, I do not want this autoscroll – acrespo Mar 11 '16 at 20:05
  • 5
    @acrespo thanks for your comment. For your issue, please add `android:descendantFocusability="blocksDescendants"` in the first `RelativeLayout` under the `NestedScrollView` – BNK Mar 12 '16 at 01:55
  • 1
    Wow! Thanks for your quick reply @BNK! That totally did it. – acrespo Mar 14 '16 at 13:53
  • 1
    @BNK Scrolling is working, but even in your sample it stucks when user start scrolling from recyclerView. So in default case if user made a long swipe from bottom, whole view would scrolled to down maximally, but if we had nested scrollView over recycler view it would scrolled in a few pixels and stuck. So i still don't have a solution except old one via headers in RV adapter – Beloo Apr 28 '16 at 10:27
  • 4
    if i put recycleview inside NestedScrollView it calling bindviewholder for all row – andro May 19 '16 at 11:21
  • @andro thanks for your comment, I have seen that too – BNK May 23 '16 at 09:31
  • @andro I have started a bounty on your question, hope that someone helps you find a working solution – BNK Jun 01 '16 at 01:39
  • 1
    Thanks for "android:descendantFocusability="blocksDescendants" ! – Vitalii Movchan Oct 14 '16 at 16:25
  • 1
    as mentioned, all the rows are being bound (so if i have 100 items, bindViewholder is called 100 times) since the nestedscrollview expands to fill the height of RV (with all item loaded), no matter if match or wrap content. That's the logic of NestedScrollView, but is there still no workaround for that? – usernotnull Sep 03 '17 at 17:04
26

Here is solution to call server only when you are realy need to load more data. In this way you can put your endless RecyclerView and many other views inside NestedScrollView. For me it is working well.

1. Create EndlessParentScrollListener class to handle scroll events from NestedSrollView.

public abstract class EndlessParentScrollListener implements NestedScrollView.OnScrollChangeListener {
        // The current offset index of data you have loaded
        private int currentPage = 0;
        // The total number of items in the dataset after the last load
        private int previousTotalItemCount = 0;
        // True if we are still waiting for the last set of data to load.
        private boolean loading = true;
        // Sets the starting page index
        private int startingPageIndex = 0;
        // The minimum amount of pixels to have below your current scroll position
        // before loading more.
        private int visibleThresholdDistance = 300;

        RecyclerView.LayoutManager mLayoutManager;

        public EndlessParentScrollListener(RecyclerView.LayoutManager layoutManager) {
            this.mLayoutManager = layoutManager;
        }

        @Override
        public void onScrollChange(NestedScrollView scrollView, int x, int y, int oldx, int oldy) {
            // We take the last son in the scrollview
            View view = scrollView.getChildAt(scrollView.getChildCount() - 1);
            int distanceToEnd = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY()));

            int totalItemCount = mLayoutManager.getItemCount();
            // If the total item count is zero and the previous isn't, assume the
            // list is invalidated and should be reset back to initial state
            if (totalItemCount < previousTotalItemCount) {
                this.currentPage = this.startingPageIndex;
                this.previousTotalItemCount = totalItemCount;
                if (totalItemCount == 0) {
                    this.loading = true;
                }
            }

            // If it’s still loading, we check to see if the dataset count has
            // changed, if so we conclude it has finished loading and update the current page
            // number and total item count.
            if (loading && (totalItemCount > previousTotalItemCount)) {
                loading = false;
                previousTotalItemCount = totalItemCount;
            }

            // If it isn’t currently loading, we check to see if we have breached
            // the visibleThreshold and need to reload more data.
            // If we do need to reload some more data, we execute onLoadMore to fetch the data.
            // threshold should reflect how many total columns there are too
            if (!loading && distanceToEnd <= visibleThresholdDistance) {
                currentPage++;
                onLoadMore(currentPage, totalItemCount);
                loading = true;
            }
        }

        // Defines the process for actually loading more data based on page
        public abstract void onLoadMore(int page, int totalItemsCount);
    }

2. Set listener

private void initRecycler() {  
        //TODO init recycler adapter here

        recycler.setNestedScrollingEnabled(false);          
        LinearLayoutManager _layoutManager = new LinearLayoutManager(this);
        recycler.setLayoutManager(_layoutManager);
        NestedScrollView scrollView = (NestedScrollView) findViewById(R.id.scrollView);
        scrollView.setOnScrollChangeListener(new EndlessParentScrollListener(_layoutManager) {
                @Override
                public void onLoadMore(int page, int totalItemsCount) {                     
                    if (loadedItemCount < serverItemsCount)
                        customLoadMoreDataFromApi();
                }
            });
        customLoadMoreDataFromApi();
    }

Short xml if someone find it usefull:

<android.support.design.widget.CoordinatorLayout 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="@android:color/background_light"
        android:fitsSystemWindows="true">


        <android.support.design.widget.AppBarLayout>
            ...
        </android.support.design.widget.AppBarLayout>

        <android.support.v4.widget.NestedScrollView
            android:id="@+id/scrollView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            android:scrollbars="vertical"
            android:scrollbarAlwaysDrawVerticalTrack="true"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:scrollbarAlwaysDrawVerticalTrack="false"
                android:scrollbars="vertical">

                <!-- some views goes here-->

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/recyclerFeed"
                    android:scrollbars="vertical"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

                <!-- and possibly here-->

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

    </android.support.design.widget.CoordinatorLayout>
andre719mv
  • 1,478
  • 13
  • 14
  • @mmlooloo you should submit this answer – inthy Sep 15 '16 at 10:31
  • 2
    is all children of the RecyclerView still visible due to being a child of NestedScrollView and would cause OutOfMemoryException like this? or it is safe? – dgngulcan Sep 26 '16 at 07:03
  • Hello ! By using your advice, I've almost reach to my goals ! But I have still facing some trivial(?) problem. When I call [loadMore], device stop for a moment. During the instance, i can't scolling or any other touching. Of course it is just really really temporary but it is on my mind continuously. Could you give me any recommend~? – JungHoon Dec 12 '16 at 03:22
  • Inside of loadMore you need to load your data in Asynchronous Background Thread. Not in UI thread. This is what you can start from: http://www.androidhive.info/2012/03/android-listview-with-load-more-button/ – andre719mv Dec 13 '16 at 08:50
  • 1
    Thank you, you saved me. I wish I could up vote this many times – Dark Leonhart Jan 20 '17 at 06:35
  • @dgngulcan, may be they are visible. But I used this approach in production many times and never got OutOfMemoryException. – andre719mv Jun 26 '17 at 22:14
  • Work Like Charm. Nice approach to do this on ScrollView and NestedScrollView. – Abhinav Suman Dec 16 '17 at 13:39
  • @andre719mv Your solution was working . but app heap size was increasing when i load more data then it caused to Out Of Memory error. – Anantha Babu Jan 09 '18 at 07:25
10

So put RecyclerView inside NestedScrollView directly will unfortunately display nothing. However, there is a way to put the recyclerview inside the NestedScrollView indirectly - just use a frameLayout as the third party to hold your recyclerview.

This is the framelayout which holds the nested recyclerview in your activity class:

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context=".ExampleFragment"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

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

Put your fragment into the framelayout (code sits within the activity class):

 ExampleFragment exampleFragment = new ExampleFragment();

    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.add(R.id.container, exampleFragment);
    ft.commit();

In your exampleFragment, you can then put your recyclerview.

<?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/post_container"
        android:background="#E0E0E0">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/my_recycler_view"
                android:scrollbars="vertical"

                android:layout_width="match_parent"
                android:layout_height="match_parent">
            </android.support.v7.widget.RecyclerView>


    </RelativeLayout>

This is the fragment code:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    super.onCreateView(inflater, container, savedInstanceState);
            llLayout = (RelativeLayout) inflater.inflate(R.layout.example_fragment_layout, container, false);
                    mRecyclerView = (RecyclerView) llLayout.findViewById(R.id.my_recycler_view);

The following is the CheeseSquare XML layout you should have:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/detail_backdrop_height"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:fitsSystemWindows="true">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleMarginEnd="64dp">

            <ImageView
                android:id="@+id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_collapseMode="pin" />

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

   <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context=".ExampleFragment"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

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

    <android.support.design.widget.FloatingActionButton
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        app:layout_anchor="@id/appbar"
        app:layout_anchorGravity="bottom|right|end"
        android:src="@drawable/ic_discuss"
        android:layout_margin="@dimen/fab_margin"
        android:clickable="true"/>

</android.support.design.widget.CoordinatorLayout>
Simon
  • 19,658
  • 27
  • 149
  • 217
  • not working, I have posted the detail layout of cheesesquare, which I put the recyclerview inside the framelayout. check edited question – mmlooloo Nov 03 '15 at 08:05
  • But my answer does not put the recyclerview into the framelayout. It has an outer framelayout with an embedded inner nestedscrollview. We are loading the fragment into the framelayout and the fragment is the one that contains the recyclerview. – Simon Nov 03 '15 at 08:19
  • I can not understand your answer. can you edit the activity detail layout. just clone the cheesesquare and put the recyclerview of CheeseListFragment into CheeseDetailActivity. – mmlooloo Nov 03 '15 at 08:23
  • I have changed your cheesesquare xml layout to include the layout that it should include. – Simon Nov 03 '15 at 08:30
  • thank you so much! the bounty will be awarded automatically as I have accepted. – mmlooloo Nov 03 '15 at 08:52
  • in cheesesquare it works, but for main project I do not know so far. – mmlooloo Nov 03 '15 at 08:58
  • I think the answer of BNK is better and there is no need for adding another viewgroup. – mmlooloo Nov 04 '15 at 04:13
  • I don't think my solution is more complex then BNK - we are both adding more depth into your layout hierarchy. He does it by enclosing a recyclerview inside a linearlayout inside a nestedscrollview. I'm doing it by enclosing a nestedscrollview into a framelayout and then inflating the fragment into the framelayout. In my example, my xml code is actually simplier and easier to maintain. – Simon Nov 04 '15 at 07:32
  • @Simon: recylcerview can be directly inside nestedscrollview, however, as in my 1st updated answer, it should be the only child of nestedscrollview. If having many other views, need to set fixed length for recyclerview, but if too many views or views have big height, recyclerview does not display. – BNK Nov 04 '15 at 23:49
  • how to handling for load more android with collapsing toolbar with nestedscroll of recycelrview android please help – Harsha Aug 18 '16 at 14:42
0

I have wasted at least a week behind this and the only solution that works is to remove the nestedscrollview. I know that is not the answer to this particular question of adding recyclerview inside nestedscrollview, but to make the recyclerview to actually recycle the view, you HAVE TO REMOVE the nestedscrollview. If you happen to have multiple view inside instead of just the recyclerview, You have to add them as items of the recyclerview by setting different viewholders, and then adding

app:layout_behavior="@string/appbar_scrolling_view_behavior"

to the recyclerview or the parent of recyclerview(the parent cannot have any other view other than Recyclerview for this to work).

In my case, the requirement was as follows:

  <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:fitsSystemWindows="true"
        app:layout_constraintTop_toTopOf="parent">

        <!-- Scrollable view here -->

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

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

                <androidx.appcompat.widget.Toolbar
                    ....>

                    <include
                        android:id="@+id/toolbar_header_view"
                        .... />
                </androidx.appcompat.widget.Toolbar>

                <include layout="@layout/widget_header" />
            </com.google.android.material.appbar.CollapsingToolbarLayout>
        </com.google.android.material.appbar.AppBarLayout>

        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            ....>
            <LinearLayout orientation="vertical" ....>
                <View .../>  <!-- I needed to have these two views along with recyclerview and i wanted them to do nestedscroll along with recyclerview -->
                <View .../>
                <androidx.recyclerview.widget.RecyclerView
                .... />
        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

I needed to have two views before recyclerview and I wanted them to do nestedscroll along with recyclerview. The only thing that worked was by removing these to views and adding them as the first two items of recyclerview, and then adding

app:layout_behavior="@string/appbar_scrolling_view_behavior"

to the swipetorefresh layout

Hope this helps someone. I will add more info If required.

hushed_voice
  • 3,161
  • 3
  • 34
  • 66