当我用适配器设置 RecyclerView 完成显示其项目时,是否有回调?
Is there a callback for when RecyclerView has finished showing its items after I've set it with an adapter?
背景
我制作了一个显示 RecyclerView 快速滚动条的库(here,以防万一),我想决定何时显示以及何时隐藏快速滚动条。
我认为一个不错的决定是,如果有项目没有显示在屏幕上(或者有很多项目没有出现),在 RecyclerView 完成其布局过程后,我将设置快速滚动条可见,如果所有项目都已显示,则无需显示。
问题
我找不到 RecyclerView 的 listener/callback 来告诉我它何时显示完项目,以便我可以检查显示的项目数与项目数相比。
当键盘出现和隐藏时,recyclerView 也可能改变它的大小。
我试过的
滚动侦听器可能无济于事,因为它发生了 "all the time",我只需要检查 RecyclerView 何时更改其大小或项目计数(或数据)何时更改。
我可以用一个布局来包装 RecyclerView,通知我尺寸的变化,比如我所做的 this one,但我认为它不会起作用,因为 RecyclerView 可能还没有准备好还不知道有多少项目是可见的。
检查显示的项目数量的方法可以这样使用:
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
...
Log.d("AppLog", "visible items count:" + (layoutManager.findLastVisibleItemPosition() -layoutManager.findFirstVisibleItemPosition()+1));
问题
我如何在 recyclerView 显示完其子视图时收到通知,以便我可以根据当前显示的内容来决定 show/hide 快速滚动器?
我找到了解决这个问题的方法(感谢用户 pskink),方法是使用 LayoutManager 的回调:
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
@Override
public void onLayoutChildren(final Recycler recycler, final State state) {
super.onLayoutChildren(recycler, state);
//TODO if the items are filtered, considered hiding the fast scroller here
final int firstVisibleItemPosition = findFirstVisibleItemPosition();
if (firstVisibleItemPosition != 0) {
// this avoids trying to handle un-needed calls
if (firstVisibleItemPosition == -1)
//not initialized, or no items shown, so hide fast-scroller
mFastScroller.setVisibility(View.GONE);
return;
}
final int lastVisibleItemPosition = findLastVisibleItemPosition();
int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
//if all items are shown, hide the fast-scroller
mFastScroller.setVisibility(mAdapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
}
};
这里的好处是它运行良好,甚至可以处理键盘 shown/hidden。
不好的是它会在不感兴趣的情况下被调用(意味着它有误报),但它不像滚动事件那么频繁,所以对我来说已经足够了。
编辑:后来添加了一个更好的回调,它不会被多次调用。这是新代码,而不是我上面写的代码:
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
@Override
public void onLayoutCompleted(final State state) {
super.onLayoutCompleted(state);
final int firstVisibleItemPosition = findFirstVisibleItemPosition();
final int lastVisibleItemPosition = findLastVisibleItemPosition();
int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
//if all items are shown, hide the fast-scroller
fastScroller.setVisibility(adapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
}
});
我为此使用 'addOnGlobalLayoutListener'。这是我的例子:
定义一个接口来执行加载后所需的操作:
public interface RecyclerViewReadyCallback {
void onLayoutReady();
}
在 RecyclerView 上,我在加载准备就绪时触发了 onLayoutReady 方法:
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
if (recyclerViewReadyCallback != null) {
recyclerViewReadyCallback.onLayoutReady();
}
recyclerViewReadyCallback = null;
});
注意:设置为null是为了防止方法被多次调用。
将此留在这里作为替代方法。在某些情况下可能有用。您还可以使用 LinearLayoutManager
s onScrollStateChanged()
并检查滚动条何时空闲。
有一点要记住,当你第一次加载你的视图时,它不会被调用,只有当用户开始滚动并且滚动完成时,才会被触发。
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext(),
RecyclerView.HORIZONTAL, false) {
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
if (state == RecyclerView.SCROLL_STATE_IDLE) {
// your logic goes here
}
}
}
};
适合我的解决方案。在使用项目初始化 RecyclerView 后需要做一些事情。
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
viewModel.onListReady()
adapter.unregisterAdapterDataObserver(this)
}
})
背景
我制作了一个显示 RecyclerView 快速滚动条的库(here,以防万一),我想决定何时显示以及何时隐藏快速滚动条。
我认为一个不错的决定是,如果有项目没有显示在屏幕上(或者有很多项目没有出现),在 RecyclerView 完成其布局过程后,我将设置快速滚动条可见,如果所有项目都已显示,则无需显示。
问题
我找不到 RecyclerView 的 listener/callback 来告诉我它何时显示完项目,以便我可以检查显示的项目数与项目数相比。
当键盘出现和隐藏时,recyclerView 也可能改变它的大小。
我试过的
滚动侦听器可能无济于事,因为它发生了 "all the time",我只需要检查 RecyclerView 何时更改其大小或项目计数(或数据)何时更改。
我可以用一个布局来包装 RecyclerView,通知我尺寸的变化,比如我所做的 this one,但我认为它不会起作用,因为 RecyclerView 可能还没有准备好还不知道有多少项目是可见的。
检查显示的项目数量的方法可以这样使用:
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
...
Log.d("AppLog", "visible items count:" + (layoutManager.findLastVisibleItemPosition() -layoutManager.findFirstVisibleItemPosition()+1));
问题
我如何在 recyclerView 显示完其子视图时收到通知,以便我可以根据当前显示的内容来决定 show/hide 快速滚动器?
我找到了解决这个问题的方法(感谢用户 pskink),方法是使用 LayoutManager 的回调:
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
@Override
public void onLayoutChildren(final Recycler recycler, final State state) {
super.onLayoutChildren(recycler, state);
//TODO if the items are filtered, considered hiding the fast scroller here
final int firstVisibleItemPosition = findFirstVisibleItemPosition();
if (firstVisibleItemPosition != 0) {
// this avoids trying to handle un-needed calls
if (firstVisibleItemPosition == -1)
//not initialized, or no items shown, so hide fast-scroller
mFastScroller.setVisibility(View.GONE);
return;
}
final int lastVisibleItemPosition = findLastVisibleItemPosition();
int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
//if all items are shown, hide the fast-scroller
mFastScroller.setVisibility(mAdapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
}
};
这里的好处是它运行良好,甚至可以处理键盘 shown/hidden。
不好的是它会在不感兴趣的情况下被调用(意味着它有误报),但它不像滚动事件那么频繁,所以对我来说已经足够了。
编辑:后来添加了一个更好的回调,它不会被多次调用。这是新代码,而不是我上面写的代码:
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
@Override
public void onLayoutCompleted(final State state) {
super.onLayoutCompleted(state);
final int firstVisibleItemPosition = findFirstVisibleItemPosition();
final int lastVisibleItemPosition = findLastVisibleItemPosition();
int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
//if all items are shown, hide the fast-scroller
fastScroller.setVisibility(adapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
}
});
我为此使用 'addOnGlobalLayoutListener'。这是我的例子:
定义一个接口来执行加载后所需的操作:
public interface RecyclerViewReadyCallback {
void onLayoutReady();
}
在 RecyclerView 上,我在加载准备就绪时触发了 onLayoutReady 方法:
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
if (recyclerViewReadyCallback != null) {
recyclerViewReadyCallback.onLayoutReady();
}
recyclerViewReadyCallback = null;
});
注意:设置为null是为了防止方法被多次调用。
将此留在这里作为替代方法。在某些情况下可能有用。您还可以使用 LinearLayoutManager
s onScrollStateChanged()
并检查滚动条何时空闲。
有一点要记住,当你第一次加载你的视图时,它不会被调用,只有当用户开始滚动并且滚动完成时,才会被触发。
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext(),
RecyclerView.HORIZONTAL, false) {
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
if (state == RecyclerView.SCROLL_STATE_IDLE) {
// your logic goes here
}
}
}
};
适合我的解决方案。在使用项目初始化 RecyclerView 后需要做一些事情。
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
viewModel.onListReady()
adapter.unregisterAdapterDataObserver(this)
}
})