首页 > 解决方案 > Infinite/Circular Recyclerview,smothScrollToPosition 指向错误的索引

问题描述

我正在尝试实现无限/循环recyclerview,这是Adapter类的实现。

    public class MyAdapter extends
        RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private static final String TAG = MyAdapter.class.getSimpleName();

    private static final int VIEW_TYPE_NORMAL = 1;

    private static final int VIEW_TYPE_GAP = 2;

    private Context mContext;

    private final List<ChannelInfo> mChannelInfoList;

    private LinearTunerClickListener mClickListener;

    public MyAdapter(
            Context context, List<ChannelInfo> channelInfoList, LinearTunerClickListener mClickListener) {
        mChannelInfoList = channelInfoList;
        mContext = context;
        this.mClickListener = mClickListener;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        //Variable to store inflated view based on VIEW TYPE.
        View inflatedView;

        BaseHolder baseHolder;

        if (viewType == VIEW_TYPE_NORMAL) {
            inflatedView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.item_some_holder1, parent, false);
            baseHolder = new SomeHolder1(inflatedView);
        } else {
            inflatedView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.item_some_holder2, parent, false);
            baseHolder = new SomeHolder2(inflatedView);
        }

        return baseHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder myViewHolder, int position) {

        if (mContext != null) {

            if (mChannelInfoList != null) {

                mPos = position % mChannelInfoList.size();

               // do stuff
            }

        }

    }

    @Override
    public int getItemViewType(int position) {
        bPos = position % mChannelInfoList.size();
        int viewType;
        if (bPos != mChannelInfoList.size() - 1) {
            viewType = VIEW_TYPE_NORMAL;
        } else {
            // If current position is last item, then return view type as GAP
            viewType = VIEW_TYPE_GAP;
        }
        return viewType;
    }

    @Override
    public int getItemCount() {
        return Integer.MAX_VALUE;
    }

}

这是持有适配器并采用索引的类(从包滚动所需的位置)

 public class MainActivity extends AppCompatActivity implements SomeListener {
        private static final String TAG = "MainActivity" + " : ";
        @BindView(R.id.activity_main2_rv)
        RecyclerView mRecyclerView;

    private MyAdapter mAdapter;
    private List<ChannelInfo> mChannelInfoList = new ArrayList<>();

    private SnapHelper mSnapHelper;
    private CenterLayoutManager mLayoutManager;
    private Integer mIndex;
    private String mChannelNo;

    private int mFocusPos = -1;
    private View mFocusedView;
    private int pos = -1;
    private int BIG = Integer.MAX_VALUE;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.linear);
        ButterKnife.bind(this);
        Log.e(TAG, "onCreate(): ");

        bundleOperation();
        setUpRecycler();
        setUpSnapHelper();
        setAdapter();


        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                if (mLayoutManager != null) {


                    mLayoutManager.scrollToPosition(Integer.MAX_VALUE/2);
                    mRecyclerView.smoothScrollToPosition(Integer.MAX_VALUE/2 + (mIndex-3));


                }
            }
        }, 300);

    }


    private void bundleOperation() {
        Bundle bundle = getIntent().getExtras();
        if (bundle != null) {
            Log.d(TAG, "get Bundle: ");
            mIndex = bundle.getInt("index");
            mChannelNo = bundle.getString("ch_no");
            Log.v(TAG, " we have,  " + " index : " + mIndex + " and " + " ch_no : " + mChannelNo);
            mChannelInfoList = bundle.getParcelableArrayList("list");

        }

    }

    private void setUpRecycler() {
        mLayoutManager = new CenterLayoutManager(
                this,
                CenterLayoutManager.HORIZONTAL,
                false
        );
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());

    }

    private void setUpSnapHelper() {
        mSnapHelper = new LinearSnapHelper();
        mSnapHelper.attachToRecyclerView(mRecyclerView);
    }

    private void setAdapter() {
        mAdapter = new MyAdapter(this, mChannelInfoList, this);
        mRecyclerView.setAdapter(mAdapter);
        mAdapter.notifyDataSetChanged();
    }

}

仅供参考,我使用了一个自定义布局管理器来实现轮播效果,所以现在假设我的列表大小共有 12 个项目,现在

  mLayoutManager.scrollToPosition(Integer.MAX_VALUE/2);
                mRecyclerView.smoothScrollToPosition(Integer.MAX_VALUE/2 + (mIndex-3));

逻辑工作正常。------------

现在,如果我修改列表,比如添加更多项目或删除它们,那么逻辑就会惨遭失败。

它完全错过了索引。

你能提示我在哪里调试或类似的,绊倒了好几个小时。如果您需要 Center Layout Manager 类,

    public class CenterLayoutManager extends LinearLayoutManager {

    private static final float BALANCING_FACTOR = 0.78f;

    private static final float fastScrollSpeedFactor = 50f;

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

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

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

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                       int position) {


        RecyclerView.SmoothScroller smoothScroller =
                new CenterSmoothScroller(recyclerView.getContext()) {


                    @Override
                    protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
                        return fastScrollSpeedFactor / displayMetrics.densityDpi;
                    }

                };

        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);

    }

    @Override
    public PointF computeScrollVectorForPosition(int targetPosition) {
        return super.computeScrollVectorForPosition(targetPosition);
    }

    @Override
    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
                                    RecyclerView.State state) {
        int scrolled = super.scrollHorizontallyBy(dx, recycler, state);

       // some logic to show center item, ZOOMED in
        return scrolled;
    }


    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        super.onLayoutChildren(recycler, state);
      //  scrollHorizontallyBy(0, recycler, state);
    }

    private static class CenterSmoothScroller extends LinearSmoothScroller {

        CenterSmoothScroller(Context context) {
            super(context);
        }


        @Override
        public int calculateDtToFit(int viewStart, int viewEnd, int boxStart,
                                    int boxEnd, int snapPreference) {
            return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
        }
    }

}

请询问我是否需要更广泛的场景来掌握情况,如果不涵盖上述场景,请尽量避免直接放置链接引用。谢谢

标签: androidandroid-recyclerview

解决方案


推荐阅读