How to snap to particular position of LinearSnapHelper in horizontal RecyclerView?

橙三吉。 提交于 2021-02-10 03:18:20

问题


How can I snap to particular position for LinearSnapHelper() in horizontal RecyclerView? There is a function scrolltoposition for RecyclerView which scroll to that position but did not keep it in center for this snaphelper.

I am looking for something like below image. So when I set to particular position, it will keep it in center. I dont find anything related to select position for SnapHelper

i find this , but this doesn't help me. Any help would be appreciated.


回答1:


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




回答2:


If I understand your question, you are looking for a way to jump to a position and have that position centered in the RecyclerView.

Maybe you have tried RecyclerView.scrollToPosition() but that doesn't snap to the view. You may also have tried RecyclerView.smoothScrollToPosition() and that works better but you may want to avoid all the movement if you have a lot of items and are scrolling a long way.

The reason that scrollToPosition() doesn't work is that it doesn't trigger the LinearSnapHelper which uses a scroll listener to detect when to snap. Since smoothScrollToPosition() does trigger the LinearSnapHelper, we will use scrollToPosition() to get us in the area of the target view then use smoothScrollToPosition() to get the view centered as follows:

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);
    }
}

Sample app

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;
}



回答3:


Add this where ever you want to scroll your recycler view

 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));
        }
    }

By using this LinearSnap Helper which is attached to your recycler view

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


来源:https://stackoverflow.com/questions/51495651/how-to-snap-to-particular-position-of-linearsnaphelper-in-horizontal-recyclervie

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!