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