web-dev-qa-db-fra.com

Comment insérer RecyclerView dans NestedScrollView?

Avec la création de NestedScrollView , vous pouvez placer une vue défilante dans une autre vue défilante, à condition que celle-ci implémente correctement NestedScrollingChild et NestedScrollingParent .

(Ce n'est pas un mauvais modèle "Ian Lake (de Google) recommande en fait de placer un RecyclerView dans un nid de défilement ici: plus.google.com/u/0/+AndroidDevelopers/posts/9kZ3SsXdT2T")

Je veux mettre RecyclerView à l'intérieur NestedScrollView et heureusement, RecyclerView implémente NestedScrollingChild afin que vous puissiez le placer à l'intérieur NestedScrollView .

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild

J'ai lu ces posts:

Comment utiliser RecyclerView dans NestedScrollView?

NestedScrolling avec NestedScrollView, RecyclerView (Horizontal), dans une CoordinatorLayout

Mais le problème avec la solution la plus votée est, il appelle tous les éléments de RecyclerView ainsi, par exemple, s'il s'agit d'un RecyclerView sans fin et lorsque l'utilisateur atteint la fin de la liste, vous voulez faire une demande réseau puis avec cette solution, le RecyclerView appelle le serveur à plusieurs reprises car il atteint automatiquement le dernier élément de RecyclerView.

Quoi qu'il en soit, comment définir le paramètre pour que je puisse mettre RecyclerView à l'intérieur de NestedScrollView. (En fait, je veux mettre un groupe de visualisation comme framelayout ou relativelayout comme un seul enfant de nestedscrollview et ensuite, je veux mettre recyclerview framelayout ou relativelayout)

Quand je mets RecyclerView à l'intérieur de NestedScrollView, il n'y a rien à afficher.


Afin de créer un exemple de projet, vous pouvez utiliser cheesesquare et changer le CheeseDetailActivity pour avoir un RecyclerView.


Bien que la réponse de BNK ne soit pas correcte, BNK a beaucoup essayé. Alors je lui décerne la prime. Toujours à la recherche d'une solution intéressante ....

55
mmlooloo

Voici ma nouvelle réponse mise à jour:

<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>

En activité:

        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

J'ai également mis à jour vers exemple de projet de My GitHub

Capture d'écran:

enter image description here


35
BNK

Voici la solution pour appeler le serveur uniquement lorsque vous devez réellement charger plus de données. De cette façon, vous pouvez insérer votre infinie RecyclerView et de nombreuses autres vues dans NestedScrollView. Pour moi ça marche bien.

1. Créez EndlessParentScrollListener classe pour gérer les événements de défilement à partir de 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. Définir un auditeur

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 si quelqu'un le trouve utile:

<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>
21
andre719mv

Donc, placer RecyclerView dans NestedScrollView directement n’affiche malheureusement rien. Cependant, il existe un moyen de placer indirectement la vue de recyclage dans NestedScrollView - il suffit d'utiliser un frameLayout en tant que tierce partie pour gérer votre vue de recyclage.

C'est le framelayout qui contient la vue de recyclage imbriquée dans votre activité classe:

    <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>

Mettez votre fragment dans le framelayout (le code est situé dans la activité classe):

 ExampleFragment exampleFragment = new ExampleFragment();

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

Dans votre exampleFragment, vous pouvez ensuite mettre votre récapitulatif de recyclage.

<?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>

C'est le 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);

Ce qui suit est la disposition XML CheeseSquare que vous devriez avoir:

<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>
10
Simon