Как разместить RecyclerView внутри NestedScrollView?
С созданием NestedScrollView вы можете поместить прокрутку в другое прокручиваемое представление, если они реализуют NestedScrollingChild и NestedScrollingParent правильно.
(Это неплохой шаблон дизайна "Янь-Лейк" (от Google) на самом деле рекомендует помещать RecyclerView
внутри вложенного просмотра: plus.google.com/u/0/+AndroidDevelopers/posts/9kZ3SsXdT2T ")
Я хочу поставить RecyclerView внутри NestedScrollView и, к счастью, RecyclerView реализует NestedScrollingChild, поэтому вы можете поместить его внутри NestedScrollView.
public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild
Я прочитал эти сообщения:
Как использовать RecyclerView внутри NestedScrollView?
NestedScrolling с помощью NestedScrollView, RecyclerView (по горизонтали) внутри координатораLayout
Но проблема с большинством проголосовавших решений состоит в том, что она вызывает все элементы RecyclerView
, например, если это бесконечное RecyclerView, и когда пользователь достигает конца списка, который вы хотите сделать сетевым, тогда с это решение RecyclerView
вызывает сервер повторно, потому что оно автоматически достигает последнего элемента RecyclerView
.
В любом случае, как установить параметр, чтобы я мог поместить RecyclerView
внутрь NestedScrollView
. (на самом деле я хочу поставить группу просмотра как framelayout или relativelayout в качестве одного дочернего элемента nestedscrollview, а затем я хочу поместить recyclerview внутри framelayout или relativelayout )
Когда я помещаю RecyclerView
внутри NestedScrollView
, ничего не видно.
Чтобы создать образец проекта, вы можете использовать cheesesquare и изменить CheeseDetailActivity
на наличие RecyclerView.
Хотя ответ BNK неверен, но BNK много пробовал. Поэтому я награждаю его щедростью. Все еще ищет хорошее решение....
Ответы
Ответ 1
Следующий мой новый обновленный ответ:
<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
Я также обновился до Пример моего проекта GitHub
Скриншот:
![введите описание изображения здесь]()
Ответ 2
Вот решение для вызова сервера только тогда, когда вам действительно нужно загрузить больше данных. Таким образом, вы можете разместить бесконечное RecyclerView и многие другие виды внутри NestedScrollView. Для меня это хорошо работает.
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>
Ответ 3
Таким образом, RetyclerView внутри NestedScrollView будет, к сожалению, ничего не показывать. Тем не менее, есть способ поместить recyclerview внутри NestedScrollView косвенно - просто используйте frameLayout в качестве третьей стороны для хранения вашего recyclerview.
Это frameelayout, который содержит вложенный recyclerview в вашем классе activity:
<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 (код находится в классе activity):
ExampleFragment exampleFragment = new ExampleFragment();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.container, exampleFragment);
ft.commit();
В exampleFragment вы можете переустановить его.
<?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);
Ниже представлен XML-макет CheeseSquare, который вы должны иметь:
<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>