Android 横向列表滑动自动选中,RecyclerView实现;

RecyclerView实现横向滑动后自动选中条目,点击其它条目自动移动到中间位置并选中;

横向的列表就是上面的效果,下面是动图;

效果就是这样的 , 有当前选中回调 , 也可以设置当前选中的条目;

代码无封装,看着更直观;

  • 获取中间位置,这个位置就是Item需要停留到的位置;
  • 滑动后计算出距离中间位置最近的一个Item , 然后让此Item滑动到居中位置;
  • 点击其它条目时 , 计算此条目距离中间的位置 , 然后滑动到中间;
  • 可以选中第一个条目和最后一个条目 ,使用隐藏的View填充;

 1、获取中间位置:

recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }

                centerToLiftDistance = recyclerView.getWidth() / 2;

            }
        });

2、滑动后计算需要移动的Item:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
                    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
                    int fi = linearLayoutManager.findFirstVisibleItemPosition();
                    int la = linearLayoutManager.findLastVisibleItemPosition();
                    Log.i("ccb", "onScrollStateChanged:首个item: " + fi + "  末尾item:" + la);
                    if (isTouch) {
                        isTouch = false;
                        //获取最中间的Item View
                        int centerPositionDiffer = (la - fi) / 2;
                        int centerChildViewPosition = fi + centerPositionDiffer; //获取当前所有条目中中间的一个条目索引
                        centerViewItems.clear();
                        //遍历循环,获取到和中线相差最小的条目索引(精准查找最居中的条目)
                        if (centerChildViewPosition != 0){
                            for (int i = centerChildViewPosition -1 ; i < centerChildViewPosition+2; i++) {
                                View cView = recyclerView.getLayoutManager().findViewByPosition(i);
                                int viewLeft = cView.getLeft()+(cView.getWidth()/2);
                                centerViewItems.add(new CenterItemUtils.CenterViewItem(i ,Math.abs(centerToLiftDistance - viewLeft)));
                            }

                            CenterItemUtils.CenterViewItem centerViewItem = CenterItemUtils.getMinDifferItem(centerViewItems);
                            centerChildViewPosition = centerViewItem.position;
                        }

                        scrollToCenter(centerChildViewPosition);
                    }
                }
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                
            }
        });

        recyclerView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                isTouch = true;
                return false;
            }
        });
 private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator();
    /**
     * 移动指定索引到中心处 , 只可以移动可见区域的内容
     * @param position
     */
    private void scrollToCenter(int position){
        position = position < childViewHalfCount ? childViewHalfCount : position;
        position = position < mAdapter.getItemCount() - childViewHalfCount -1 ? position : mAdapter.getItemCount() - childViewHalfCount -1;

        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        View childView = linearLayoutManager.findViewByPosition(position);
        Log.i("ccb", "滑动后中间View的索引: " + position);
        //把当前View移动到居中位置
        if (childView == null) return;
        int childVhalf = childView.getWidth() / 2;
        int childViewLeft = childView.getLeft();
        int viewCTop = centerToLiftDistance;
        int smoothDistance = childViewLeft - viewCTop + childVhalf;
        Log.i("ccb", "\n居中位置距离左部距离: " + viewCTop
                + "\n当前居中控件距离左部距离: " + childViewLeft
                + "\n当前居中控件的一半高度: " + childVhalf
                + "\n滑动后再次移动距离: " + smoothDistance);
        recyclerView.smoothScrollBy(smoothDistance, 0,decelerateInterpolator);
        mAdapter.setSelectPosition(position);

        tv.setText("当前选中:" + mDatas.get(position));
    }

3、点击选中:

 final int fp = position;
            vh.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    scrollToCenter(fp);
                    Toast.makeText(HorizontalSelectActivity.this, "点击" + mDatas.get(fp), Toast.LENGTH_SHORT).show();
                }
            });

4、选中第一个和最后一个:

int childViewHeight = UiUtils.dip2px(HorizontalSelectActivity.this, CHILDVIEWSIZE); //43是当前已知的 Item的高度
                childViewHalfCount = (recyclerView.getWidth() / childViewHeight + 1) / 2;
if (mDatas == null) mDatas = new ArrayList<>();
        for (int i = 0; i < 55; i++) {
            mDatas.add("条目" + i);
        }
        for (int j = 0; j < childViewHalfCount; j++) { //头部的空布局
            mDatas.add(0, null);
        }
        for (int k = 0; k < childViewHalfCount; k++) {  //尾部的空布局
            mDatas.add(null);
        }
if (TextUtils.isEmpty(mDatas.get(position))){
                vh.itemView.setVisibility(View.INVISIBLE);
            }else {
                vh.itemView.setVisibility(View.VISIBLE);
                vh.tv.setText(mDatas.get(position));
            }

OK , 以上只是主要代码和大致思路,全部的代码请移步到

CSDN:https://download.csdn.net/download/qq_35605213/12470655

Github:https://github.com/CuiChenbo/ArcSelectList , 欢迎Star

同理 , 竖直的列表也是这样实现:

实现九宫格横向左右滑动的功能,可以使用 RecyclerView 和 GridLayoutManager 来实现。以下是具体步骤: 1. 在布局文件中,添加 RecyclerView 控件: ```xml <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="horizontal" /> ``` 2. 在代码中,初始化 RecyclerView 和 GridLayoutManager,并设置相关属性: ```java RecyclerView recyclerView = findViewById(R.id.recycler_view); GridLayoutManager layoutManager = new GridLayoutManager(this, 3); // 设置列数为3 layoutManager.setOrientation(RecyclerView.HORIZONTAL); // 设置水平滚动 recyclerView.setLayoutManager(layoutManager); int spacing = getResources().getDimensionPixelSize(R.dimen.grid_spacing); // 设置item之间的间距 recyclerView.addItemDecoration(new GridSpacingItemDecoration(3, spacing, true)); // 通过自定义ItemDecoration来实现 ``` 其中,GridSpacingItemDecoration 是自定义的一个 RecyclerView.ItemDecoration,用来设置 item 之间的间距,具体实现如下: ```java public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { private int spanCount; private int spacing; private boolean includeEdge; public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) { this.spanCount = spanCount; this.spacing = spacing; this.includeEdge = includeEdge; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { int position = parent.getChildAdapterPosition(view); // item position int column = position % spanCount; // item column if (includeEdge) { outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing) outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing) if (position < spanCount) { // top edge outRect.top = spacing; } outRect.bottom = spacing; // item bottom } else { outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing) outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing) if (position >= spanCount) { outRect.top = spacing; // item top } } } } ``` 3. 创建 RecyclerView.Adapter 和 RecyclerView.ViewHolder,并在 onBindViewHolder() 方法中设置 item 的内容: ```java public class GridAdapter extends RecyclerView.Adapter<GridAdapter.GridViewHolder> { private List<Integer> dataList; // 数据源 public GridAdapter(List<Integer> dataList) { this.dataList = dataList; } @NonNull @Override public GridViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_grid, parent, false); return new GridViewHolder(view); } @Override public void onBindViewHolder(@NonNull GridViewHolder holder, int position) { holder.imageView.setImageResource(dataList.get(position)); // 设置图片资源 } @Override public int getItemCount() { return dataList.size(); } static class GridViewHolder extends RecyclerView.ViewHolder { ImageView imageView; GridViewHolder(View itemView) { super(itemView); imageView = itemView.findViewById(R.id.image_view); } } } ``` 4. 最后在 Activity 中设置 RecyclerView 的 adapter: ```java List<Integer> dataList = new ArrayList<>(); // 数据源 dataList.add(R.drawable.pic1); dataList.add(R.drawable.pic2); dataList.add(R.drawable.pic3); dataList.add(R.drawable.pic4); dataList.add(R.drawable.pic5); dataList.add(R.drawable.pic6); dataList.add(R.drawable.pic7); dataList.add(R.drawable.pic8); dataList.add(R.drawable.pic9); GridAdapter adapter = new GridAdapter(dataList); recyclerView.setAdapter(adapter); ``` 这样就可以实现九宫格横向左右滑动的效果了。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值