erd*_*dna 323 android listview onscrolllistener material-design android-recyclerview
我想换ListView到RecyclerView.我想使用onScroll的的OnScrollListener在RecyclerView确定用户滚动到列表的末尾.
如何知道用户是否滚动到列表末尾以便我可以从REST服务获取新数据?
Abd*_*oor 401
感谢@Kushal,这就是我实现它的方式
private boolean loading = true;
int pastVisiblesItems, visibleItemCount, totalItemCount;
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy)
{
if(dy > 0) //check for scroll down
{
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
if (loading)
{
if ( (visibleItemCount + pastVisiblesItems) >= totalItemCount)
{
loading = false;
Log.v("...", "Last Item Wow !");
//Do pagination.. i.e. fetch new data
}
}
}
}
});
Run Code Online (Sandbox Code Playgroud)
别忘了添加
LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
Run Code Online (Sandbox Code Playgroud)
Kus*_*rma 160
制作这些变量.
private int previousTotal = 0;
private boolean loading = true;
private int visibleThreshold = 5;
int firstVisibleItem, visibleItemCount, totalItemCount;
Run Code Online (Sandbox Code Playgroud)
在Scroll上设置回收站视图.
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = mRecyclerView.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
Log.i("Yaeye!", "end called");
// Do something
loading = true;
}
}
});
Run Code Online (Sandbox Code Playgroud)
注意:确保您使用的
LinearLayoutManager是布局管理器RecyclerView.
LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
Run Code Online (Sandbox Code Playgroud)
并为一个网格
GridLayoutManager mLayoutManager;
mLayoutManager = new GridLayoutManager(getActivity(), spanCount);
mRecyclerView.setLayoutManager(mLayoutManager);
Run Code Online (Sandbox Code Playgroud)
享受无尽的卷轴!^.^
更新: mRecyclerView.不推荐使用
setOnScrollListener(),只需替换为mRecyclerView.addOnScrollListener(),警告就会消失!您可以从这个SO问题中阅读更多内容.
由于Android现在正式支持Kotlin,这里有相同的更新 -
制作OnScrollListener
class OnScrollListener(val layoutManager: LinearLayoutManager, val adapter: RecyclerView.Adapter<RecyclerAdapter.ViewHolder>, val dataList: MutableList<Int>) : RecyclerView.OnScrollListener() {
var previousTotal = 0
var loading = true
val visibleThreshold = 10
var firstVisibleItem = 0
var visibleItemCount = 0
var totalItemCount = 0
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
visibleItemCount = recyclerView.childCount
totalItemCount = layoutManager.itemCount
firstVisibleItem = layoutManager.findFirstVisibleItemPosition()
if (loading) {
if (totalItemCount > previousTotal) {
loading = false
previousTotal = totalItemCount
}
}
if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
val initialSize = dataList.size
updateDataList(dataList)
val updatedSize = dataList.size
recyclerView.post { adapter.notifyItemRangeInserted(initialSize, updatedSize) }
loading = true
}
}
}
Run Code Online (Sandbox Code Playgroud)
并将其添加到您的RecyclerView中
recyclerView.addOnScrollListener(OnScrollListener(layoutManager, adapter, dataList))
Run Code Online (Sandbox Code Playgroud)
有关完整的代码示例,请随时参考此Github仓库.
Hai*_*ang 70
对于那些只想在完全显示最后一项时获得通知的人,您可以使用View.canScrollVertically().
这是我的实现:
public abstract class OnVerticalScrollListener
extends RecyclerView.OnScrollListener {
@Override
public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (!recyclerView.canScrollVertically(-1)) {
onScrolledToTop();
} else if (!recyclerView.canScrollVertically(1)) {
onScrolledToBottom();
} else if (dy < 0) {
onScrolledUp();
} else if (dy > 0) {
onScrolledDown();
}
}
public void onScrolledUp() {}
public void onScrolledDown() {}
public void onScrolledToTop() {}
public void onScrolledToBottom() {}
}
Run Code Online (Sandbox Code Playgroud)
注意:recyclerView.getLayoutManager().canScrollVertically()如果您想支持API <14,则可以使用.
Sab*_*med 64
这是另一种方法.它适用于任何布局管理器.
为了详细了解,我写了一篇博文和示例项目,请点击这里 http://sab99r.com/blog/recyclerview-endless-load-more/
MyAdapter.java
public abstract class MyAdapter extends RecyclerView.Adapter<ViewHolder>{
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//check for last item
if ((position >= getItemCount() - 1))
load();
}
public abstract void load();
}
Run Code Online (Sandbox Code Playgroud)
MyActivity.java
public class MainActivity extends AppCompatActivity {
List<Items> items;
MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
adapter=new MyAdapter(items){
@Override
public void load() {
//implement your load more here
Item lastItem=items.get(items.size()-1);
loadMore();
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
Fed*_*nzi 17
我的回答是Noor的修改版本.我从ListView我所拥有的地方EndlessScrollListener(你可以很容易地在很多答案中找到)传递给RecyclerView我,所以我希望EndlessRecyclScrollListener能够轻松地更新我过去的听众.
所以这是代码,希望它有所帮助:
public abstract class EndlessScrollRecyclListener extends RecyclerView.OnScrollListener
{
// The total number of items in the dataset after the last load
private int previousTotalItemCount = 0;
private boolean loading = true;
private int visibleThreshold = 5;
int firstVisibleItem, visibleItemCount, totalItemCount;
private int startingPageIndex = 0;
private int currentPage = 0;
@Override
public void onScrolled(RecyclerView mRecyclerView, int dx, int dy)
{
super.onScrolled(mRecyclerView, dx, dy);
LinearLayoutManager mLayoutManager = (LinearLayoutManager) mRecyclerView
.getLayoutManager();
visibleItemCount = mRecyclerView.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
onScroll(firstVisibleItem, visibleItemCount, totalItemCount);
}
public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
// 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;
currentPage++;
}
// 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.
if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem +
visibleThreshold))
{
onLoadMore(currentPage + 1, totalItemCount);
loading = true;
}
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page, int totalItemsCount);
}
Run Code Online (Sandbox Code Playgroud)
Min*_*yen 10
对我来说,这很简单:
private boolean mLoading = false;
mList.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int totalItem = mLinearLayoutManager.getItemCount();
int lastVisibleItem = mLinearLayoutManager.findLastVisibleItemPosition();
if (!mLoading && lastVisibleItem == totalItem - 1) {
mLoading = true;
// Scrolled to bottom. Do something here.
mLoading = false;
}
}
});
Run Code Online (Sandbox Code Playgroud)
注意异步作业:必须在异步作业结束时更改mLoading.希望它会有所帮助!
大多数答案是假设RecyclerView使用a LinearLayoutManager,或者GridLayoutManager甚至StaggeredGridLayoutManager,或者假设滚动是垂直或水平的,但没有人发布完整的通用答案.
使用ViewHolder适配器显然不是一个好的解决方案.适配器RecyclerView使用它可能有多于1个.它"适应"他们的内容.它应该是Recycler View(它是负责当前向用户显示的内容的一个类,而不是仅负责提供内容的适配器RecyclerView),它必须通知您的系统需要更多项目(到加载).
这是我的解决方案,只使用RecyclerView(RecycerView.LayoutManager和RecycerView.Adapter)的抽象类:
/**
* Listener to callback when the last item of the adpater is visible to the user.
* It should then be the time to load more items.
**/
public abstract class LastItemListener extends RecyclerView.OnScrollListener {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// init
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (layoutManager.getChildCount() > 0) {
// Calculations..
int indexOfLastItemViewVisible = layoutManager.getChildCount() -1;
View lastItemViewVisible = layoutManager.getChildAt(indexOfLastItemViewVisible);
int adapterPosition = layoutManager.getPosition(lastItemViewVisible);
boolean isLastItemVisible = (adapterPosition == adapter.getItemCount() -1);
// check
if (isLastItemVisible)
onLastItemVisible(); // callback
}
}
/**
* Here you should load more items because user is seeing the last item of the list.
* Advice: you should add a bollean value to the class
* so that the method {@link #onLastItemVisible()} will be triggered only once
* and not every time the user touch the screen ;)
**/
public abstract void onLastItemVisible();
}
// --- Exemple of use ---
myRecyclerView.setOnScrollListener(new LastItemListener() {
public void onLastItemVisible() {
// start to load more items here.
}
}
Run Code Online (Sandbox Code Playgroud)
借助 Kotlin 扩展函数的强大功能,代码可以看起来更加优雅。把它放在任何你想要的地方(我把它放在一个 ExtensionFunctions.kt 文件中):
/**
* WARNING: This assumes the layout manager is a LinearLayoutManager
*/
fun RecyclerView.addOnScrolledToEnd(onScrolledToEnd: () -> Unit){
this.addOnScrollListener(object: RecyclerView.OnScrollListener(){
private val VISIBLE_THRESHOLD = 5
private var loading = true
private var previousTotal = 0
override fun onScrollStateChanged(recyclerView: RecyclerView,
newState: Int) {
with(layoutManager as LinearLayoutManager){
val visibleItemCount = childCount
val totalItemCount = itemCount
val firstVisibleItem = findFirstVisibleItemPosition()
if (loading && totalItemCount > previousTotal){
loading = false
previousTotal = totalItemCount
}
if(!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)){
onScrolledToEnd()
loading = true
}
}
}
})
}
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它:
youRecyclerView.addOnScrolledToEnd {
//What you want to do once the end is reached
}
Run Code Online (Sandbox Code Playgroud)
此解决方案基于 Kushal Sharma 的回答。但是,这要好一些,因为:
onScrollStateChanged代替onScroll. 这更好,因为onScroll每次在 RecyclerView 中发生任何类型的移动时onScrollStateChanged都会调用,而仅在 RecyclerView 的状态更改时调用。使用onScrollStateChanged将节省您的 CPU 时间,从而节省电池。尽管接受的答案完美无缺,但下面的解决方案使用addOnScrollListener,因为不推荐使用setOnScrollListener,并且减少了变量的数量,并且条件也是如此.
final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
feedsRecyclerView.setLayoutManager(layoutManager);
feedsRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) {
if ((layoutManager.getChildCount() + layoutManager.findFirstVisibleItemPosition()) >= layoutManager.getItemCount()) {
Log.d("TAG", "End of list");
//loadMore();
}
}
}
});
Run Code Online (Sandbox Code Playgroud)
好的,我是通过使用RecyclerView.Adapter的onBindViewHolder方法做到的。
适配器:
public interface OnViewHolderListener {
void onRequestedLastItem();
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
...
if (position == getItemCount() - 1) onViewHolderListener.onRequestedLastItem();
}
Run Code Online (Sandbox Code Playgroud)
片段(或活动):
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
contentView = inflater.inflate(R.layout.comments_list, container, false);
recyclerView = (RecyclerView) mContentView.findViewById(R.id.my_recycler_view);
adapter = new Adapter();
recyclerView.setAdapter(adapter);
...
adapter.setOnViewHolderListener(new Adapter.OnViewHolderListener() {
@Override
public void onRequestedLastItem() {
//TODO fetch new data from webservice
}
});
return contentView;
}
Run Code Online (Sandbox Code Playgroud)
小智 5
虽然这个问题有很多答案,但我想分享我们创建无尽列表视图的经验.我们最近实现了自定义Carousel LayoutManager,它可以通过无限滚动列表以及某个点来在循环中工作.以下是GitHub的详细说明.
我建议你看看这篇文章,其中包含有关创建自定义LayoutManagers的简短但有价值的建议:http://cases.azoft.com/create-custom-layoutmanager-android/
这是我的操作方式,简单而简短:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy)
{
if(!recyclerView.canScrollVertically(1) && dy != 0)
{
// Load more results here
}
}
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
212100 次 |
| 最近记录: |