我有一个在RecyclerView
内的CardView
。 CardView
的高度为500dp,但如果RecyclerView
较小,我想缩短这个高度。因此我想知道当RecyclerView
第一次完成放置物品时是否有任何听众被调用,使得有可能将RecyclerView
的高度设置为CardView
的高度(如果小于500dp)。
在我的Recycler视图完成对所有元素的膨胀之后,我还需要执行代码。我尝试在我的适配器中检查onBindViewHolder
,如果位置是最后一个,然后通知观察者。但在那时,回收者的观点仍然没有完全填充。
由于RecyclerView实施ViewGroup
,this anwser非常有帮助。您只需要将一个OnGlobalLayoutListener添加到recyclerView:
View recyclerView = findViewById(R.id.myView);
recyclerView.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//At this point the layout is complete and the
//dimensions of recyclerView and any child views are known.
//Remove listener after changed RecyclerView's height to prevent infinite loop
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
工作修改@andrino答案。
正如@Juancho在上面的评论中指出的那样。这种方法被多次调用。在这种情况下,我们希望它只被触发一次。
使用实例创建自定义侦听器,例如
private RecyclerViewReadyCallback recyclerViewReadyCallback;
public interface RecyclerViewReadyCallback {
void onLayoutReady();
}
然后在你的OnGlobalLayoutListener
上设置RecyclerView
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (recyclerViewReadyCallback != null) {
recyclerViewReadyCallback.onLayoutReady();
}
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
之后,您只需要使用您的代码实现自定义侦听器
recyclerViewReadyCallback = new RecyclerViewReadyCallback() {
@Override
public void onLayoutReady() {
//
//here comes your code that will be executed after all items are laid down
//
}
};
如果你使用Kotlin,那么有一个更紧凑的解决方案。来自here的样品。 此布局侦听器通常用于在测量View之后执行某些操作,因此通常需要等到宽度和高度大于0。 ...它可以被任何扩展View的对象使用,并且还能够从侦听器访问其所有特定的功能和属性。
// define 'afterMeasured' layout listener:
inline fun <T: View> T.afterMeasured(crossinline f: T.() -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (measuredWidth > 0 && measuredHeight > 0) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
f()
}
}
})
}
// using 'afterMeasured' handler:
recycler.afterMeasured {
// do the scroll (you can use the RecyclerView functions and properties directly)
// ...
}
一旦它被触发,我一直在努力尝试移除OnGlobalLayoutListener
,但这会引发IllegalStateException
。因为我需要的是将我的recyclerView滚动到第二个元素,我所做的是检查它是否已经有了孩子,如果这是第一次这是真的,那么我只做滚动:
public class MyActivity extends BaseActivity implements BalanceView {
...
private boolean firstTime = true;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
ViewTreeObserver vto = myRecyclerView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (myRecyclerView.getChildCount() > 0 && MyActivity.this.firstTime){
MyActivity.this.firstTime = false;
scrollToSecondPosition();
}
}
});
}
...
private void scrollToSecondPosition() {
// do the scroll
}
}
HTH有人!
(当然,这是受到@andrino和@Phatee答案的启发)
同样在相同的情况下,您可以使用RecyclerView.post()
方法在弹出列表/网格项后运行代码。在我的情况下,它已经足够了。
// Another way
// Get the values
Maybe<List<itemClass>> getItemClass(){
return /* */
}
// Create a listener
void getAll(DisposableMaybeObserver<List<itemClass>> dmo) {
getItemClass().subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(dmo);
}
// In the code where you want to track the end of loading in recyclerView:
DisposableMaybeObserver<List<itemClass>> mSubscriber = new DisposableMaybeObserver<List<itemClass>>() {
@Override
public void onSuccess(List<itemClass> item_list) {
adapter.setWords(item_list);
adapter.notifyDataSetChanged();
Log.d("RECYCLER", "DONE");
}
@Override
public void onError(Throwable e) {
Log.d("RECYCLER", "ERROR " + e.getMessage());
}
@Override
public void onComplete() {
Log.d("RECYCLER", "COMPLETE");
}
};
void getAll(mSubscriber);
//and
@Override
public void onDestroy() {
super.onDestroy();
mSubscriber.dispose();
Log.d("RECYCLER","onDestroy");
}
recyclerView.getChildAt(recyclerView.getChildCount() - 1).postDelayed(new Runnable() {
@Override
public void run() {
//do something
}
}, 300);
RecyclerView一次只列出特定数量的项目,我们可以通过调用getChildCount()来获取该数字。接下来,我们需要通过调用getChildAt(int index)来获取最后一项。索引是getChildCount() - 1。
我受到这个人的回答的启发,我再也找不到他的帖子了。他说如果你想对最后一项做些什么,使用postDelayed()而不是普通的post()很重要。我认为这是为了避免NullPointerException。 300是以ms为单位的延迟时间。您可以将其更改为50,就像那个人那样。
对我有用的是在设置RecyclerView适配器后添加监听器。
ServerRequest serverRequest = new ServerRequest(this);
serverRequest.fetchAnswersInBackground(question_id, new AnswersDataCallBack()
{
@Override
public void done(ArrayList<AnswerObject> returnedListOfAnswers)
{
mAdapter = new ForumAnswerRecyclerViewAdapter(returnedListOfAnswers, ForumAnswerActivity.this);
recyclerView.setAdapter(mAdapter);
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
progressDialog.dismiss();
}
});
}
});
在全局布局状态或视图树中视图的可见性发生更改后,这将取消“progressDialog”。