RecyclerView+PagerSnapHelper实现横向图片列表左右滑动效果

笔者要实现的效果描述如下:
一组图片横向排列,焦点图片在屏幕中间展示,两端要显示上个图片和下个图片的部分,具体效果如下面图片所示:

                                图一. 图片滑到最右边时的效果

在这里插入图片描述

                                图二. 图片滑到最左边时的效果

在这里插入图片描述

                                图三. 图片滑到中间时的效果

在这里插入图片描述
最终采用RecyclerView + PagerSnapHelper来实现此种效果,这里只记录几个要点。

1、自定义PagerSnapHelper,使得要显示在屏幕中央的图片可以居中显示,主要实现方法 calculateDistanceToFinalSnap()

    @Override
    public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) targetView.getLayoutParams();
        int position = params.getViewAdapterPosition();
        int left = targetView.getLeft();
        int right = targetView.getRight();
        int top = targetView.getTop();
        int bottom = targetView.getBottom();
        ViewGroup viewGroup = (ViewGroup) targetView.getParent();

        int[] out = new int[]{0, 0};
        boolean isLastItem;
        if (mOrientation == LinearLayoutManager.HORIZONTAL) {
            isLastItem = position == layoutManager.getItemCount() - 1/*最后一个*/ && right == viewGroup.getMeasuredWidth();
            if (layoutManager.canScrollHorizontally()) {
                out[0] = distanceToCenter(layoutManager, targetView,
                        OrientationHelper.createHorizontalHelper(layoutManager));//***这里让图片居于屏幕的中间***
                out[1] = 0;
            } 
        } else {
            isLastItem = position == layoutManager.getItemCount() - 1/*最后一个*/ && bottom == viewGroup.getMeasuredHeight();
            out[0] = 0;
            out[1] = top;
        }

        
            mCurrentPosition = position;
            mOnPageListener.onPageSelector(mCurrentPosition);
            mOnPageListener.onPageSelector(currentPosition, mCurrentPosition);
        }
        return out;
    }

    private int distanceToCenter(@NonNull RecyclerView.LayoutManager layoutManager,
                                 @NonNull View targetView, OrientationHelper helper) {
        //找到targetView的中心坐标
        final int childCenter = helper.getDecoratedStart(targetView) +
                (helper.getDecoratedMeasurement(targetView) / 2);
        final int containerCenter;
        //找到容器(RecyclerView)的中心坐标
        if (layoutManager.getClipToPadding()) {
            containerCenter = helper.getStartAfterPadding() + helper.getTotalSpace() / 2;
        } else {
            containerCenter = helper.getEnd() / 2;
        }
        //两个中心坐标的差值就是targetView需要滚动的距离
        return childCenter - containerCenter;
    }

2、除了第一步的操作之外,还需要进行额外操作,否则会发现图片两端是撑到屏幕边缘的,那么如何让图片两端可以露出上一个图片和下一个图片的一部分呢?这里可以在图片recyclerView的adapter中,设置下图片item的宽度来实现。

 @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View convertView = LayoutInflater.from(mContext).inflate(R.layout.home_adapter_item, parent, false);
        RelativeLayout rootRl = (RelativeLayout) convertView.findViewById(R.id.rl_root);
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(scrrenWidth - DensityUtil.dp2px(40f), DensityUtil.dp2px(150f));//***这里设备图片item根布局的固定高度为150dp,宽度为屏幕宽度减去40dp,设置合适的宽度就可以让前一幅图片和后一幅图片露出一部分了;***
        layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
        rootRl.setLayoutParams(layoutParams);

        return new HomeRoomAdapter.RoomViewHolder(convertView);
    }

3、实现文章开头展示的效果,还缺最后一个步,即如何让第一幅图片的左边距要大些,让最后一幅图片的右边距要大些?这里可以修改下自定义的RecyclerView.ItemDecoration,调整下第一个位置的左边距和最后一个位置的右边距来实现。

public class HomeSpaceItemDecoration extends RecyclerView.ItemDecoration {

        private int space;

        public HomeSpaceItemDecoration(int space) {
            this.space = space;
        }

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            int position = parent.getChildAdapterPosition(view);
            int childCount = parent.getAdapter().getItemCount();
            if (childCount > 1) {
                if (position == 0) {
                    outRect.left = space * 4;//***第一个item距离屏幕左边距要设置的大些***
                    outRect.right = space;
                } else if (position == childCount - 1) {
                    outRect.left = space;
                    outRect.right = space * 4;//***最后一个item距离屏幕右边距要设置的大些***
                } else {
                    outRect.left = space;//中间item的左右边距
                    outRect.right = space;
                }
            }
        }
    }

至此,经过上面三个步骤,文章顶部的图示效果就可以实现啦。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值