繁体   English   中英

如何在水平 RecyclerView 中捕捉到 LinearSnapHelper 的特定 position?

[英]How to snap to particular position of LinearSnapHelper in horizontal RecyclerView?

如何在水平 RecyclerView 中为 LinearSnapHelper() 捕捉到特定的 position? RecyclerView 有一个 function scrolltoposition 滚动到该 position 但没有将其保持在此 snaphelper 的中心。

我正在寻找类似下图的东西。 因此,当我设置为特定的 position 时,它将保持居中。 我没有找到与 SnapHelper 的 select position相关的任何内容

我找到了这个,但这对我没有帮助。 任何帮助,将不胜感激。

在此处输入图像描述

如果我理解您的问题,您正在寻找一种方法来跳转到 position 并让 position 以RecyclerView为中心。

也许您已经尝试过RecyclerView.scrollToPosition()但这并没有捕捉到视图。 您可能也尝试过RecyclerView.smoothScrollToPosition()并且效果更好,但是如果您有很多项目并且滚动很长的路,您可能希望避免所有移动。

scrollToPosition()不起作用的原因是它不会触发使用滚动侦听器来检测何时捕捉的LinearSnapHelper 由于smoothScrollToPosition()确实触发了LinearSnapHelper ,我们将使用scrollToPosition()让我们进入目标视图的区域,然后使用smoothScrollToPosition()让视图居中,如下所示:

private RecyclerView mRecycler;

private void newScrollTo(final int pos) {
    RecyclerView.ViewHolder vh = mRecycler.findViewHolderForLayoutPosition(pos);
    if (vh != null) {
        // Target view is available, so just scroll to it.
        mRecycler.smoothScrollToPosition(pos);
    } else {
        // Target view is not available. Scroll to it.
        mRecycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
            // From the documentation:
            // This callback will also be called if visible item range changes after a layout
            // calculation. In that case, dx and dy will be 0.This callback will also be called
            // if visible item range changes after a layout calculation. In that case,
            // dx and dy will be 0.
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                mRecycler.removeOnScrollListener(this);
                if (dx == 0) {
                    newScrollTo(pos);
                }
            }
        });
        mRecycler.scrollToPosition(pos);
    }
}

示例应用

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private final LinearLayoutManager mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
    private final List<String> mItems = new ArrayList<>();
    private RecyclerView mRecycler;
    private final int mItemCount = 2000;
    private final Handler mHandler = new Handler();
    private final LinearSnapHelper mLinearSnapHelper = new LinearSnapHelper();

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        for (int i = 0; i < mItemCount; i++) {
            mItems.add(i + "");
        }

        mRecycler = findViewById(R.id.recyclerView);
        final RecyclerViewAdapter adapter = new RecyclerViewAdapter(null);
        adapter.setItems(mItems);
        mRecycler.setLayoutManager(mLayoutManager);
        mRecycler.setAdapter(adapter);
        mLinearSnapHelper.attachToRecyclerView(mRecycler);
        newScrollTo(1);
//        fireScrollTo();
    }

    private int maxScrolls = mItemCount;

    private void fireScrollTo() {
        if (--maxScrolls > 0) {
            int pos = (int) (Math.random() * mItemCount);
            newScrollTo(pos);
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    fireScrollTo();
                }
            }, 2000);
        }
    }

    private void newScrollTo(final int pos) {
        mRecycler.smoothScrollToPosition(pos);
        RecyclerView.ViewHolder vh = mRecycler.findViewHolderForLayoutPosition(pos);
        if (vh != null) {
            // Target view is available, so just scroll to it.
            mRecycler.smoothScrollToPosition(pos);
        } else {
            // Target view is not available. Scroll to it.
            mRecycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
                // From the documentation:
                // This callback will also be called if visible item range changes after a layout
                // calculation. In that case, dx and dy will be 0.This callback will also be called
                // if visible item range changes after a layout calculation. In that case,
                // dx and dy will be 0.
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    mRecycler.removeOnScrollListener(this);
                    if (dx == 0) {
                        newScrollTo(pos);
                    }
                }
            });
            mRecycler.scrollToPosition(pos);
        }
    }
}

activity_main.xml

<android.support.constraint.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:layout_width="3px"
        android:layout_height="match_parent"
        android:background="@android:color/holo_red_light"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:paddingStart="660px"
        android:paddingEnd="660px"/>

</android.support.constraint.ConstraintLayout>

RecyclerViewAdapter.java

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private List<String> mItems;

    RecyclerViewAdapter(List<String> items) {
        mItems = items;
    }

    @Override
    public @NonNull
    RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
        view.getLayoutParams().width = 220;
        view.getLayoutParams().height = 220;
//        view.setPadding(220 * 3, 0, 220 * 3, 0);
        ((TextView) view).setGravity(Gravity.CENTER);
        return new ItemViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        ItemViewHolder vh = (ItemViewHolder) holder;
        String itemText = mItems.get(position);

        vh.mItemTextView.setText(itemText);
        int bgColor = (position % 2 == 0)
            ? android.R.color.holo_blue_light
            : android.R.color.holo_green_light;
        holder.itemView.setBackgroundColor(
            holder.itemView.getContext().getResources().getColor(bgColor));
    }

    @Override
    public int getItemCount() {
        return (mItems == null) ? 0 : mItems.size();
    }

    @Override
    public int getItemViewType(int position) {
        return TYPE_ITEM;
    }

    static class ItemViewHolder extends RecyclerView.ViewHolder {
        private TextView mItemTextView;

        ItemViewHolder(View item) {
            super(item);
            mItemTextView = item.findViewById(android.R.id.text1);
        }
    }

    public void setItems(List<String> items) {
        mItems = items;
    }

    @SuppressWarnings("unused")
    private final static String TAG = "RecyclerViewAdapter";

    private final static int TYPE_ITEM = 1;
}

将此添加到您想要滚动回收站视图的任何位置

 recyclerView.scrollToPosition(position)
    recyclerView.post {
        var view = recyclerView.layoutManager?.findViewByPosition(position);
        if (view == null) {
          // do nothing
        }

        var snapDistance = snapHelper.calculateDistanceToFinalSnap(recyclerView.layoutManager!!, view!!)
        if (snapDistance?.get(0)   != 0 || snapDistance[1] != 0) {
            recyclerView.scrollBy(snapDistance?.get(0)!!, snapDistance?.get(1));
        }
    }

通过使用附加到您的回收站视图的此 LinearSnap Helper

  var snapHelper = LinearSnapHelper()
    snapHelper.attachToRecyclerView(recyclerView)

对于水平 RecyclerView,您应该使用PagerSnapHelper()而不是LinearSnapHelper()

刚刚做了一些研究并追踪了 SnapHelper 的源代码,结果发现解决方案可能非常简单:

class MyPagerSnapHelper: PagerSnapHelper() {

    fun smoothScrollToPosition(layoutManager: RecyclerView.LayoutManager, position: Int) {
        val smoothScroller = createScroller(layoutManager) ?: return

        smoothScroller.targetPosition = position
        layoutManager.startSmoothScroll(smoothScroller)
    }
}

然后你可以在这里传递 RecyclerView 的 LayoutManager 和目标 position

snapHelper.smoothScrollToPosition(recyclerView.layoutManager!!, index)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM