【发布时间】:2018-06-09 19:19:59
【问题描述】:
尝试了所有相关的问题,但没有奏效:(
我正在使用 Recycler View 构建无限滚动。
问题: onScrolled 方法总是在用户不滚动屏幕的情况下被调用。
Android 文档指南对 onScrolled 方法进行了描述:
Case 1) RecyclerView 被调用的回调方法 滚动。这将在滚动完成后调用。
案例 2) 如果可见项目范围发生变化,也会调用此回调 经过布局计算。在这种情况下,dx 和 dy 将为 0。
由于案例 2,我的 onScrolled 方法在没有用户滚动的情况下被调用。我在屏幕上记录了 dy,结果发现 onScrolled 是用 dy=0 调用的。这发生在第二种情况下。
如果我使用:
if (dy > 0){
// The user is scrolling down
}
事实证明,无论我滚动 Recycler 视图多少次,我的 onScrolled 方法都不会被调用。
我的代码
RecyclerAdapterSmallVideos.java
public class RecyclerAdapterSmallVideos extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<VideosBigSize> videosBigSizeList;
private Context mContext;
final int VIEW_TYPE_ITEM = 0, VIEW_TYPE_LOADING = 1;
ILoadMore loadMore;
boolean isLoading;
int visibleThreshold = 5;
int lastVisibleItem, totalItemCount;
public RecyclerAdapterSmallVideos(RecyclerView recyclerView, Context context, List<VideosBigSize> videosBigSizeList) {
this.videosBigSizeList = videosBigSizeList;
this.mContext = context;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
recyclerView.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 (loadMore != null) {
// This is running without the user scrolling the Recycler View.
loadMore.onLoadMore();
}
isLoading = true;
}
}
});
}
@Override
public int getItemViewType(int position) {
return videosBigSizeList.get(position) == null ? VIEW_TYPE_LOADING: VIEW_TYPE_ITEM;
}
public void setLoadMore(ILoadMore loadMore) {
this.loadMore = loadMore;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_small_video, parent, false);
return new ViewHolderSmallVideos(view);
} else if (viewType == VIEW_TYPE_LOADING) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, parent, false);
return new ViewHolderLoading(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
/*########### Case 1) The holder is a instance off ViewHolderSmallVideos (Items) ###########*/
if (holder instanceof ViewHolderSmallVideos) {
Log.i("Debugging", "onBindViewHolder: Binding instance of ViewHolder SmallVideos: " + holder.getAdapterPosition());
VideosBigSize singleVideoBigSize = videosBigSizeList.get(position);
ViewHolderSmallVideos viewHolderSmallVideos = (ViewHolderSmallVideos) holder;
// Step 1) Images
GlideApp.with(viewHolderSmallVideos.thumbNail.getContext())
.load(singleVideoBigSize.getThumnail_url())
.centerCrop()
.into(viewHolderSmallVideos.thumbNail); // Video Thumbnail
// Step 2) Determine the Max Length for each TextView
setTextMaxLength(viewHolderSmallVideos.videoTitle, viewHolderSmallVideos.channelName, mContext);
// Step 3) Texts
viewHolderSmallVideos.videoTitle.setText(singleVideoBigSize.getVideo_title());
viewHolderSmallVideos.channelName.setText(singleVideoBigSize.getChannel_name());
viewHolderSmallVideos.videoViews.setText(singleVideoBigSize.getVideo_views());
viewHolderSmallVideos.videoUploadDate.setText(singleVideoBigSize.getVideo_upload_date());
viewHolderSmallVideos.videoDuration.setText(singleVideoBigSize.getVideo_duration());
// Step 4) Handle clicks
viewHolderSmallVideos.constraintLayoutEachItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, String.valueOf(holder.getAdapterPosition()), Toast.LENGTH_SHORT).show();
}
});
}
/*########### Case 2) The holder is a instance off ViewHolderLoading (progressBar) ###########*/
else if (holder instanceof ViewHolderLoading) {
Log.i("Debugging", "onBindViewHolder: Binding instance of ViewHolder Loading: " + holder.getAdapterPosition());
ViewHolderLoading viewHolderLoading = (ViewHolderLoading) holder;
viewHolderLoading.progressBar.setIndeterminate(true);
}
}
/**
* Get the number of items in the adapter
* @return the number of items in the adapter
*/
@Override
public int getItemCount() { return videosBigSizeList.size(); }
public void setLoaded() {
isLoading = false;
}
/**
* Determine a maximum number of characters for the Title and Channel Name
* If they are too big and the width of the screen is too small, the text
* will get bigger than the thumbnail and then the layout will be disturbed.
* @param videoTitle the title of the video
* @param channelName the name of the channel who uploaded the video
* @param context the activity context
*/
private void setTextMaxLength(TextView videoTitle, TextView channelName, Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
if (windowManager != null) {
// Get the current width of the screen in DP
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
// 1) If the device is 420dp or less;
// 2) Limit the number of characters for the title and channel name
if (dpWidth <= 420) {
videoTitle.setFilters(new InputFilter[]{new InputFilter.LengthFilter(35)});
channelName.setFilters(new InputFilter[]{new InputFilter.LengthFilter(25)});
}
}
}
}
ProfileFragment.java
private void setupRecyclerView(final List<VideosBigSize> userAllVideosList) {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
mRecyclerView.setLayoutManager(linearLayoutManager);
mRecyclerView.setNestedScrollingEnabled(false);
final RecyclerAdapterSmallVideos adapterSmallVideos = new RecyclerAdapterSmallVideos(mRecyclerView, mContext, userAllVideosList);
mRecyclerView.setAdapter(adapterSmallVideos);
// Set Load more event
adapterSmallVideos.setLoadMore(new ILoadMore() {
@Override
public void onLoadMore() {
if (userAllVideosList.size() <= 50) {
mRecyclerView.post(new Runnable() {
@Override
public void run() {
userAllVideosList.add(null);
adapterSmallVideos.notifyItemInserted(userAllVideosList.size() - 1);
}
});
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
userAllVideosList.remove(userAllVideosList.size() - 1);
adapterSmallVideos.notifyItemRemoved(userAllVideosList.size());
// Random more data
int index = userAllVideosList.size();
int end = index + 10;
for (int i = index; i < end; i++) {
// Add more data to userAllVideosList...
adapterSmallVideos.notifyItemInserted(i);
}
adapterSmallVideos.setLoaded();
}
}, 2000);
}
// Loaded everything already
else {
Toast.makeText(mContext, "Load data completed!", Toast.LENGTH_SHORT).show();
}
}
});
}
我的 ProfileFragment 布局
fragment_profile.xml
请务必注意:
1) 我的 Recycler 视图位于 NesteScrollView 内,因为我需要隐藏/显示工具栏。记得我设置了 mRecyclerView.setNestedScrollingEnabled(false) 因为它触发了 NestedScrollView;
2) 除了回收站视图之外,我的布局中还有更多内容。
【问题讨论】:
-
您需要
onScrolled做什么?如果只是为了“分页”,请使用谷歌的paging 支持库 -
当然你需要使用
PagedListAdapter作为基类 -
谢谢你,我正在尝试实现它。我不知道这门课。但是我是否需要从数据库源中获取数据来实现 PagedListAdapter 或者我可以从任何地方实现?你有一个很好的教程吗,我看到网上没有太多的东西。
-
google for:
PagedListAdapter -stackoverflow- medium.com 上有一些很好的教程,顺便说一句,您从哪里获取数据?
标签: android xml android-recyclerview linearlayoutmanager