Recyclerview 视图不适用于 setNestedScrollingEnabled,它也从不回收任何视图
Recyclerview view is not working with setNestedScrollingEnabled and its never recycle any views also
我面临两个问题:
- 滚动侦听器将不起作用
- 当
RecyclerView
附加到 NestedScrollView
时,它从不回收任何视图。它就像 ScrollView 中的线性布局。它使用大量内存并造成滞后。
我在回收站视图顶部附加了一个 youtube 播放器片段,因为我无法将片段放入回收站视图中。在我的代码中你可以看到有一个框架布局。
我的布局是这样的:
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nestedScroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="240dp"
android:layout_alignParentTop="true"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/youtube_layout"
android:visibility="visible"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
我想使用滚动侦听器加载更多项目
所以我尝试了以下方法:
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
Log.i(TAG, "onScrolled: ");
// bail out if scrolling upward or already loading data
if (dy < 0 || dataLoading.isDataLoading()) return;
final int visibleItemCount = recyclerView.getChildCount();
final int totalItemCount = layoutManager.getItemCount();
final int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
if ((totalItemCount - visibleItemCount) <= (firstVisibleItem )) {
onLoadMore();
}
}
但是 layoutManager.findFirstVisibleItemPosition()==0
所以它不起作用,而且超过 onScrolled never called twice
因为我设置了
recyclerview.setNestedScrollingEnabled(假)
所以我在onBindView
中试过这样
public void onBindViewHolder(RecyclerView.ViewHolder customViewHolder, int i) {
Log.w("d","inside bind view");
if(i>=getItemCount()-1 && !datamanager.isDataLoading()){
datamanager.loadmoreData();
}
但是 recylerview 在我开始滚动之前一次性绑定所有视图,所以这个方法也不起作用。
这是我实现它的方法,我尝试将代码剥离到最低限度
public class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int VIEW_TYPE_LOADING = 0;
private static final int VIEW_TYPE_ITEM = 1;
public boolean isLoading;
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
public ArrayList<Data> datas;
private OnLoadMoreListener mOnLoadMoreListener;
public DataAdapter(RecyclerView mRecyclerView, ArrayList<Data> datas) {
this.datas = datas;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (mOnLoadMoreListener != null) {
DataAdapter.this.datas.remove(null);
mOnLoadMoreListener.onLoadMore();
}
}
}
});
}
public static class DataObjectHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
//your views
public DataObjectHolder(View itemView) {
super(itemView);
//initialize your views
}
@Override
public void onClick(View v) {
if (onItemClickListener != null) onItemClickListener.onItemClick(getAdapterPosition(), v);
}
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
@Override
public int getItemViewType(int position) {
return datas.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_data, parent, false);
DataObjectHolder dataObjectHolder = new DataObjectHolder(view);
return dataObjectHolder;
} else if (viewType == VIEW_TYPE_LOADING) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_loading_item, parent, false);
return new LoadingViewHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder hldr, final int position) {
if (hldr instanceof DataObjectHolder) {
final Data data = datas.get(position);
final DataObjectHolder holder = (DataObjectHolder) hldr;
//bind your views
} else if (hldr instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) hldr;
if (isLoading) {
loadingViewHolder.progressBar.setVisibility(View.VISIBLE);
loadingViewHolder.progressBar.setIndeterminate(true);
loadingViewHolder.tv_load_more.setVisibility(View.GONE);
loadingViewHolder.tv_load_more.setOnClickListener(null);
} else {
loadingViewHolder.progressBar.setVisibility(View.GONE);
loadingViewHolder.tv_load_more.setVisibility(View.VISIBLE);
loadingViewHolder.tv_load_more.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mOnLoadMoreListener != null) {
datas.remove(null);
mOnLoadMoreListener.onLoadMore();
}
}
});
}
}
}
@Override
public int getItemCount() {
return datas.size();
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
}
loadingViewHolder 的 XML 如下所示,您基本上只是膨胀以获得持有人
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp">
<ProgressBar
android:id="@+id/progressBar1"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:indeterminate="true"/>
<TextView
android:id="@+id/tv_load_more"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:text="Tap to load more"
android:textSize="14sp"/>
</RelativeLayout>
希望这对您有所帮助
The recycler view never recycle any views when its attached to nested scroll view,its acts as set on linear layout inside scroll view.its create a huge memory and lags the screen.
没错。您不能将 RecyclerView 放入另一个滚动视图中。
不行,因为wrapping view需要知道RecyclerView的总高度,而RecyclerView只能通过测量和布局它的itemall来知道它的总高度.
如何解决这个问题?
不要将 RecyclerView 放在另一个滚动视图中。
如果您需要 header 或页脚,您必须将其添加到 RecyclerView 并让 RecyclerView 负责显示它。去掉你的 ScrollView 并把你的 header 移到 RecyclerView 的 里面。
从技术上讲,也可以在 RecyclerView 中加载片段,但我不得不承认让它正常工作有点棘手。
还有很多库可以促进这个过程,我个人最喜欢的是 Epoxy made by AirBnb, but there's also Groupie,还有很多其他库。
我遇到过这种情况。有一个recyclerview。回收站视图有 viewpager。 viewpager有fragments然后fragment里面有recyclerview
您需要破解触控才能使其完美滚动。
private boolean interceptTouch = true;
private static final int MIN_DISTANCE = 200;
private float downX = 0, downY = 0, moveX = 0, moveY = 0, upX = 0, upY;
public TouchInterceptRecyclerView(Context context) {
super(context);
}
public TouchInterceptRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (getRvTop() == 0) {
onTouchEvent(ev);
}
return interceptTouch;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
moveX = event.getX();
moveY = event.getY();
break;
case MotionEvent.ACTION_UP:
upX = event.getX();
upY = event.getY();
break;
}
float deltaX = upX - downX;
if (getViewTop() == 0 && moveY > downY && Math.abs(moveY - downY) > MIN_DISTANCE) { // moving down
interceptTouch = true;
}else if (Math.abs(deltaX) > MIN_DISTANCE) {
if (upX > downX) { // Left to Right swipe action
interceptTouch = false;
}else { // Right to left swipe action
interceptTouch = false;
}
} else { // screen tap
interceptTouch = false;
}
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
}
@Override
public void onScrolled(int dx, int dy) {
if (getViewTop() <= 0) {
interceptTouch = false; // dispatch the touch to child when reached top
} else {
interceptTouch = true; // do not dispatch the touch event
}
super.onScrolled(dx, dy);
}
public int getViewTop() {
int top = 0;
View v = this.getChildAt(1);
if (v == null) {
v = this.getChildAt(0);
}
if (v != null && v instanceof LinearLayout) {
top = v.getTop();
}
return top;
}
public int getRvTop() {
int top = -1;
View v = this.getChildAt(1);
if (v == null) {
v = this.getChildAt(0);
}
if (v != null && v instanceof LinearLayout) {
ViewPager vp = (ViewPager) v.findViewById(R.id.single_tribe_pager);
if (vp != null) {
int currentPos = vp.getCurrentItem();
RecyclerView rv = (RecyclerView) vp.findViewWithTag("recyclerview" + currentPos);
if (rv != null) {
View v1 = rv.getChildAt(0);
if (v1 != null && v1 instanceof CardView) {
top = v1.getTop() - ResourceUtils.getDimensionPixelOffset(R.dimen.padding_20); // deducting 20 as we have give top margin as 20 to the top layout
}
}
}
}
return top;
}
我面临两个问题:
- 滚动侦听器将不起作用
- 当
RecyclerView
附加到NestedScrollView
时,它从不回收任何视图。它就像 ScrollView 中的线性布局。它使用大量内存并造成滞后。
我在回收站视图顶部附加了一个 youtube 播放器片段,因为我无法将片段放入回收站视图中。在我的代码中你可以看到有一个框架布局。
我的布局是这样的:
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nestedScroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="240dp"
android:layout_alignParentTop="true"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/youtube_layout"
android:visibility="visible"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
我想使用滚动侦听器加载更多项目 所以我尝试了以下方法:
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
Log.i(TAG, "onScrolled: ");
// bail out if scrolling upward or already loading data
if (dy < 0 || dataLoading.isDataLoading()) return;
final int visibleItemCount = recyclerView.getChildCount();
final int totalItemCount = layoutManager.getItemCount();
final int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
if ((totalItemCount - visibleItemCount) <= (firstVisibleItem )) {
onLoadMore();
}
}
但是 layoutManager.findFirstVisibleItemPosition()==0
所以它不起作用,而且超过 onScrolled never called twice
因为我设置了
recyclerview.setNestedScrollingEnabled(假)
所以我在onBindView
中试过这样
public void onBindViewHolder(RecyclerView.ViewHolder customViewHolder, int i) {
Log.w("d","inside bind view");
if(i>=getItemCount()-1 && !datamanager.isDataLoading()){
datamanager.loadmoreData();
}
但是 recylerview 在我开始滚动之前一次性绑定所有视图,所以这个方法也不起作用。
这是我实现它的方法,我尝试将代码剥离到最低限度
public class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int VIEW_TYPE_LOADING = 0;
private static final int VIEW_TYPE_ITEM = 1;
public boolean isLoading;
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
public ArrayList<Data> datas;
private OnLoadMoreListener mOnLoadMoreListener;
public DataAdapter(RecyclerView mRecyclerView, ArrayList<Data> datas) {
this.datas = datas;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (mOnLoadMoreListener != null) {
DataAdapter.this.datas.remove(null);
mOnLoadMoreListener.onLoadMore();
}
}
}
});
}
public static class DataObjectHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
//your views
public DataObjectHolder(View itemView) {
super(itemView);
//initialize your views
}
@Override
public void onClick(View v) {
if (onItemClickListener != null) onItemClickListener.onItemClick(getAdapterPosition(), v);
}
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
@Override
public int getItemViewType(int position) {
return datas.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_data, parent, false);
DataObjectHolder dataObjectHolder = new DataObjectHolder(view);
return dataObjectHolder;
} else if (viewType == VIEW_TYPE_LOADING) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_loading_item, parent, false);
return new LoadingViewHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder hldr, final int position) {
if (hldr instanceof DataObjectHolder) {
final Data data = datas.get(position);
final DataObjectHolder holder = (DataObjectHolder) hldr;
//bind your views
} else if (hldr instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) hldr;
if (isLoading) {
loadingViewHolder.progressBar.setVisibility(View.VISIBLE);
loadingViewHolder.progressBar.setIndeterminate(true);
loadingViewHolder.tv_load_more.setVisibility(View.GONE);
loadingViewHolder.tv_load_more.setOnClickListener(null);
} else {
loadingViewHolder.progressBar.setVisibility(View.GONE);
loadingViewHolder.tv_load_more.setVisibility(View.VISIBLE);
loadingViewHolder.tv_load_more.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mOnLoadMoreListener != null) {
datas.remove(null);
mOnLoadMoreListener.onLoadMore();
}
}
});
}
}
}
@Override
public int getItemCount() {
return datas.size();
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
}
loadingViewHolder 的 XML 如下所示,您基本上只是膨胀以获得持有人
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp">
<ProgressBar
android:id="@+id/progressBar1"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:indeterminate="true"/>
<TextView
android:id="@+id/tv_load_more"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:text="Tap to load more"
android:textSize="14sp"/>
</RelativeLayout>
希望这对您有所帮助
The recycler view never recycle any views when its attached to nested scroll view,its acts as set on linear layout inside scroll view.its create a huge memory and lags the screen.
没错。您不能将 RecyclerView 放入另一个滚动视图中。
不行,因为wrapping view需要知道RecyclerView的总高度,而RecyclerView只能通过测量和布局它的itemall来知道它的总高度.
如何解决这个问题?
不要将 RecyclerView 放在另一个滚动视图中。
如果您需要 header 或页脚,您必须将其添加到 RecyclerView 并让 RecyclerView 负责显示它。去掉你的 ScrollView 并把你的 header 移到 RecyclerView 的 里面。
从技术上讲,也可以在 RecyclerView 中加载片段,但我不得不承认让它正常工作有点棘手。
还有很多库可以促进这个过程,我个人最喜欢的是 Epoxy made by AirBnb, but there's also Groupie,还有很多其他库。
我遇到过这种情况。有一个recyclerview。回收站视图有 viewpager。 viewpager有fragments然后fragment里面有recyclerview
您需要破解触控才能使其完美滚动。
private boolean interceptTouch = true;
private static final int MIN_DISTANCE = 200;
private float downX = 0, downY = 0, moveX = 0, moveY = 0, upX = 0, upY;
public TouchInterceptRecyclerView(Context context) {
super(context);
}
public TouchInterceptRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (getRvTop() == 0) {
onTouchEvent(ev);
}
return interceptTouch;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
moveX = event.getX();
moveY = event.getY();
break;
case MotionEvent.ACTION_UP:
upX = event.getX();
upY = event.getY();
break;
}
float deltaX = upX - downX;
if (getViewTop() == 0 && moveY > downY && Math.abs(moveY - downY) > MIN_DISTANCE) { // moving down
interceptTouch = true;
}else if (Math.abs(deltaX) > MIN_DISTANCE) {
if (upX > downX) { // Left to Right swipe action
interceptTouch = false;
}else { // Right to left swipe action
interceptTouch = false;
}
} else { // screen tap
interceptTouch = false;
}
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
}
@Override
public void onScrolled(int dx, int dy) {
if (getViewTop() <= 0) {
interceptTouch = false; // dispatch the touch to child when reached top
} else {
interceptTouch = true; // do not dispatch the touch event
}
super.onScrolled(dx, dy);
}
public int getViewTop() {
int top = 0;
View v = this.getChildAt(1);
if (v == null) {
v = this.getChildAt(0);
}
if (v != null && v instanceof LinearLayout) {
top = v.getTop();
}
return top;
}
public int getRvTop() {
int top = -1;
View v = this.getChildAt(1);
if (v == null) {
v = this.getChildAt(0);
}
if (v != null && v instanceof LinearLayout) {
ViewPager vp = (ViewPager) v.findViewById(R.id.single_tribe_pager);
if (vp != null) {
int currentPos = vp.getCurrentItem();
RecyclerView rv = (RecyclerView) vp.findViewWithTag("recyclerview" + currentPos);
if (rv != null) {
View v1 = rv.getChildAt(0);
if (v1 != null && v1 instanceof CardView) {
top = v1.getTop() - ResourceUtils.getDimensionPixelOffset(R.dimen.padding_20); // deducting 20 as we have give top margin as 20 to the top layout
}
}
}
}
return top;
}