创建NestedScrollView后,只要正确执行NestedScrollingChild和NestedScrollingParent,您就可以将滚动视图放在另一个滚动视图中。
(这是一个不错的设计模式" Ian Lake(来自Google)实际上建议在这里将RecyclerView
置于nestedscrollview中:plus.google.com/u/0/+AndroidDevelopers/posts/9kZ3SsXdT2T& #34;)
我想将RecyclerView放在NestedScrollView内,幸运的是RecyclerView实现了NestedScrollingChild,因此您可以将其放在NestedScrollView内。
public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild
我已阅读这些帖子:
How to use RecyclerView inside NestedScrollView?
NestedScrolling with NestedScrollView, RecyclerView (Horizontal), inside a CoordinatorLayout
但是大多数投票解决方案的问题是,它调用RecyclerView
的所有项目,例如,如果它是无尽的RecyclerView,当用户到达列表的末尾时,您想要发出网络请求然后使用该解决方案RecyclerView
重复调用服务器,因为它会自动到达RecyclerView
的最后一项。
无论如何,如何设置参数以便我可以将RecyclerView
放在NestedScrollView
内。(实际上我想把一个像framelayout或relativelayout这样的视图组作为nestedscrollview的单个childe然后我想放置recyclerview在framelayout或relativelayout内)
当我将RecyclerView
放在NestedScrollView
内时,无法显示任何内容。
要创建示例项目,您可以使用cheesesquare并更改CheeseDetailActivity
以使用RecyclerView。
虽然BNK的答案不正确,但BNK已经尝试了很多。所以我授予他赏金。仍在寻找好的解决方案....
答案 0 :(得分:34)
以下是我最新的答案:
<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>
活动:
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
我还更新为My GitHub's sample project
截图:
答案 1 :(得分:21)
以下是仅在您真正需要加载更多数据时才调用服务器的解决方案。通过这种方式,您可以在NestedScrollView中放置无尽的RecyclerView和许多其他视图。对我而言,它运作良好。
1。创建 EndlessParentScrollListener 类以处理来自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. 设置侦听器
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();
}
如果有人发现它有用,请使用短xml:
<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>
答案 2 :(得分:10)
所以直接将RecyclerView直接放在NestedScrollView中会遗憾地显示任何内容。但是,有一种方法可以将recyclerview间接放入NestedScrollView中 - 只需使用frameLayout作为第三方来保存您的recyclerview。
这是framelayout,它在活动类中保存嵌套的recyclerview:
<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>
将您的片段放入 framelayout (代码位于活动类中):
ExampleFragment exampleFragment = new ExampleFragment();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.container, exampleFragment);
ft.commit();
在 exampleFragment 中,您可以放置您的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>
这是片段代码:
@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);
以下是您应该拥有的 CheeseSquare XML布局:
<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>
答案 3 :(得分:0)
我已经浪费了至少一个星期的时间,唯一可行的解决方案是删除nestedscrollview
。我知道这不是在recyclerview
内添加nestedscrollview
的特定问题的答案,但要使recyclerview实际回收视图,您必须删除 nestedscrollview
。如果您碰巧内部有多个view
而不是recyclerview
,则必须通过设置不同的观看者,然后添加
recyclerview
的项。
app:layout_behavior="@string/appbar_scrolling_view_behavior"
到recyclerview或recyclerview
的父级(父级除了Recyclerview之外,没有其他任何视图可以正常工作)。
在我的情况下,要求如下:
<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>
我需要在recyclerview
之前有两个视图,我希望它们与recyclerview
一起进行嵌套滚动。唯一有效的方法是将它们删除到视图中并将它们添加为recyclerview
的前两项,然后添加
app:layout_behavior="@string/appbar_scrolling_view_behavior"
转到swipetorefresh
布局
希望这对某人有帮助。如果需要,我将添加更多信息。