RecyclerView 中 CardView 项的滚动位置 [英] Scrolling position of the CardView items in RecyclerView

查看:32
本文介绍了RecyclerView 中 CardView 项的滚动位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在用这种方法保存和检索上次查看项目的位置挣扎了将近一天之后,我终于找到了一个可以提供所需输出的解决方案.在返回 RecyclerView 的路上打开我的一个项目后,我的应用程序滚动到该项目,但有一个小错误......我使用了两种方法 onPause() 和 onResume(),这是我的实现:

@Override受保护的无效 onPause() {super.onPause();lastFirstVisiblePosition = ((LinearLayoutManager)mRecyclerView.getLayoutManager()).findLastVisibleItemPosition();Log.d("位置", String.valueOf(lastFirstVisiblePosition));}@覆盖protected void onResume() {super.onResume();new Handler().postDelayed(new Runnable() {@覆盖公共无效运行(){mRecyclerView.scrollToPosition(lastFirstVisiblePosition);}}, 200);}

  1. 由于我是初学者,我不确定为此目的使用 Handler 是否明智?
  2. 因为我的卡片/物品大小不同,所以只要物品不在特定位置,我就无法返回到上次查看物品的位置,这意味着只要下面的物品不在屏幕上... 有什么办法可以考虑我的卡片的尺寸并根据那个设置位置吗?

要添加的另一件事我曾尝试过 onSaveInstanceState() 和 onRestoreInstanceState() 方法,但没有成功......其中一种实现:

@Overrideprotected void onSaveInstanceState(@NonNull Bundle outState) {super.onSaveInstanceState(outState);lastFirstVisiblePosition = ((LinearLayoutManager)mRecyclerView.getLayoutManager()).findLastVisibleItemPosition();outState.putString("position", String.valueOf(lastFirstVisiblePosition));Log.d("currentPos", String.valueOf(outState));}@覆盖protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);String position = savedInstanceState.getString("position");mRecyclerView.scrollToPosition(Integer.parseInt(position));}

通过这种方式,我能够获得当前位置但无法恢复它......

解决方案

  1. 由于我是初学者,我不确定为此目的使用 Handler 是否明智?

处理程序确实不是最聪明的方法,因为 200 毫秒可能不足以加载 RecyclerView 的全部数据,但是您需要使用处理程序的原因是您没有知道什么时候 RecyclerView 加载了数据,以便在你知道之后滚动到某个位置.

您的处理程序有更好的方法,但它的功能与您的相同,因为它仍然存在 200 毫秒的问题.

mRecyclerView.postDelayed(new Runnable() {@覆盖公共无效运行(){mRecyclerView.scrollToPosition(lastFirstVisiblePosition);mRecyclerView.removeCallbacks(this);}}, 200);

之所以更好是因为处理程序与您的 RecyclerView

耦合

但我建议使用而不是使用 Hanlder 的解决方案是向 LinearLayoutManager 添加一个侦听器,该侦听器在 RecyclerView 列表时触发 由适配器填充,通常是在 mAdapter.notifyDataSetChanged() 结束时.要做到这一点:

第一

创建一个自定义的 LinearLayoutManager 并添加一个监听器接口,每当 onLayoutCompleted() 被调用.

public class LayoutCompletionLinearLayoutManager extends LinearLayoutManager {公共无效setCallback(OnLayoutCompleteCallback回调){mCallback = 回调;}私有 OnLayoutCompleteCallback mCallback = null;公共 LayoutCompletionLinearLayoutManager(上下文上下文){超级(上下文);}public LayoutCompletionLinearLayoutManager(上下文上下文,int方向,布尔reverseLayout){超级(上下文,方向,reverseLayout);}public LayoutCompletionLinearLayoutManager(上下文上下文,AttributeSet attrs,int defStyleAttr,int defStyleRes){超级(上下文,属性,defStyleAttr,defStyleRes);}public void onLayoutCompleted(RecyclerView.State state) {super.onLayoutCompleted(state);如果(mCallback != null)mCallback.onLayoutComplete();}公共接口 OnLayoutCompleteCallback {void onLayoutComplete();}}

第二

在构建 RecyclerView LayoutManager 时使用回调.

final LayoutCompletionLinearLayoutManager layoutMgr =新的 LayoutCompletionLinearLayoutManager(getApplicationContext(),LinearLayoutManager.HORIZONTAL, false);//根据你的 RecyclerView 改变方向layoutMgr.setCallback(new LayoutCompletionLinearLayoutManager.OnLayoutCompleteCallback() {@覆盖公共无效 onLayoutComplete() {mRecyclerView.scrollToPosition(lastFirstVisiblePosition);layoutMgr.setCallback(null);}});mRecyclerView.setLayoutManager(layoutMgr);

<块引用>

  1. 因为我的卡片/物品大小不同,所以只要物品不在特定位置,我就无法返回到上次查看物品的位置,这意味着只要下面的物品不在屏幕上... 有什么办法可以考虑我的卡片的尺寸并根据那个设置位置吗?

您需要使用 LinearLayoutManager scrollToPositionWithOffset() 根据你的 CardView 而不是 scrollToPosition()

((LayoutCompletionLinearLayoutManager) mRecyclerView.getLayoutManager()).scrollToPositionWithOffset(lastFirstVisiblePosition, offset);

After almost a day of struggling with this method to save and retrieve the position of the last viewed item, I finally found a solution that gives me the desired output. After opening one of my items on the way back to the RecyclerView my app scrolls to that item but with a small bug... I am using 2 methods onPause() and onResume() and this is my implementation:

@Override
protected void onPause() {
    super.onPause();
    lastFirstVisiblePosition = ((LinearLayoutManager)
            mRecyclerView.getLayoutManager()).findLastVisibleItemPosition();
    Log.d("position", String.valueOf(lastFirstVisiblePosition));
}

@Override
protected void onResume() {
    super.onResume();

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            mRecyclerView.scrollToPosition(lastFirstVisiblePosition);
        }
    }, 200);

}

  1. Since I am a beginner I am not sure if using the Handler in this purpose is a smart idea?
  2. Because my cards/items are not the same sizes I am not able to return to the position of the last viewed item as long as the item is not in a certain position meaning as long as the item below is not on the screen... Is there any way to consider the dimension of my card and according to that set the position?

one more thing to add I had tried onSaveInstanceState() and onRestoreInstanceState() methods but unsuccessfully... One of the implementations:

@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);

    lastFirstVisiblePosition = ((LinearLayoutManager)
            mRecyclerView.getLayoutManager()).findLastVisibleItemPosition();
    outState.putString("position", String.valueOf(lastFirstVisiblePosition));
    Log.d("currentPos", String.valueOf(outState));

}

@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    String position = savedInstanceState.getString("position");
    mRecyclerView.scrollToPosition(Integer.parseInt(position));
}

in this way, I was able to get the current position but not to restore it...

解决方案

  1. Since I am a beginner I am not sure if using the Handler in this purpose is a smart idea?

The handler is not the smartest way indeed because the 200 msec may not sufficient to load the entire data of the RecyclerView, but the reason that you need to use a handler is that you don't know when the RecyclerView is loaded with the data in order to scroll to a certain position just after you know that.

There is a bit better way for your handler, but it function the same as yours as it still suffers the problem of the 200 msec.

mRecyclerView.postDelayed(new Runnable() {
    @Override
    public void run() {
        mRecyclerView.scrollToPosition(lastFirstVisiblePosition);
        mRecyclerView.removeCallbacks(this);
    }
}, 200);

The reason that it's better because the handler is coupled to your RecyclerView

But the solution that I recommend to use instead of using a Hanlder is to add a listener to your LinearLayoutManager that is triggered when the list of the RecyclerView is populated by the adapter, typically when the mAdapter.notifyDataSetChanged() is over. And to do that:

First

Create a custom LinearLayoutManager and add a listener interface that is triggered whenever the onLayoutCompleted() is invoked.

public class LayoutCompletionLinearLayoutManager extends LinearLayoutManager {

    public void setCallback(OnLayoutCompleteCallback callback) {
        mCallback = callback;
    }

    private OnLayoutCompleteCallback mCallback = null;

    public LayoutCompletionLinearLayoutManager(Context context) {
        super(context);
    }

    public LayoutCompletionLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    public LayoutCompletionLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public void onLayoutCompleted(RecyclerView.State state) {
        super.onLayoutCompleted(state);
        if (mCallback != null)
            mCallback.onLayoutComplete();
    }

    public interface OnLayoutCompleteCallback {
        void onLayoutComplete();
    }
}

Second

Use the callback when you build your RecyclerView LayoutManager.

final LayoutCompletionLinearLayoutManager layoutMgr = 
    new LayoutCompletionLinearLayoutManager(getApplicationContext(), 
        LinearLayoutManager.HORIZONTAL, false); // change orientation according to your RecyclerView

layoutMgr.setCallback(new LayoutCompletionLinearLayoutManager.OnLayoutCompleteCallback() {
    @Override
    public void onLayoutComplete() {
        mRecyclerView.scrollToPosition(lastFirstVisiblePosition);
        layoutMgr.setCallback(null);
    }
});

mRecyclerView.setLayoutManager(layoutMgr);

  1. Because my cards/items are not the same sizes I am not able to return to the position of the last viewed item as long as the item is not in a certain position meaning as long as the item below is not on the screen... Is there any way to consider the dimension of my card and according to that set the position?

You need to use the LinearLayoutManager scrollToPositionWithOffset() with some offset according to the dimension of your CardView instead of scrollToPosition()

((LayoutCompletionLinearLayoutManager) mRecyclerView.getLayoutManager())
    .scrollToPositionWithOffset(lastFirstVisiblePosition, offset);

这篇关于RecyclerView 中 CardView 项的滚动位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆