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

时间:2018-07-24 09:54:34

标签: android android-recyclerview kotlin pagersnaphelper

如何在水平RecyclerView中捕捉到LinearSnapHelper()的特定位置? RecyclerView有一个函数scrolltoposition,可滚动到该位置,但不会在此snaphelper中居中。

我正在寻找下图所示的内容。因此,当我设置到特定位置时,它将保持居中。我没有发现与SnapHelper

的选择职位相关的任何信息

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

enter image description here

3 个答案:

答案 0 :(得分:1)

如果我理解您的问题,那么您正在寻找一种跳到某个位置并将该位置居于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;
}

答案 1 :(得分:0)

For horizontal RecyclerView, you should use PagerSnapHelper() instead of LinearSnapHelper().

答案 2 :(得分:0)

  

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

 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)