博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
RecyclerView实现Gallery画廊效果
阅读量:5227 次
发布时间:2019-06-14

本文共 7115 字,大约阅读时间需要 23 分钟。

使用RecyclerView实现一个画廊效果,主要是使用support库中最新加入的PagerSnapHelper类,通过计算滑动偏移来计算scale的值。

585087-20170923123107821-1219561243.gif

基本实现

首先需要为RecyclerView添加一个滚动监听,然后为RecyclerView的第一个与最后一个itemView添加一个ItemDecoration,使位于第一个与最后一个itemView的位置居中对齐。

public void attachToRecyclerView(final RecyclerView recyclerView) {        this.recyclerView = recyclerView;        snapHelper.attachToRecyclerView(recyclerView);        recyclerView.addOnScrollListener(scrollListener);        recyclerView.addItemDecoration(new ScalableCardItemDecoration());        recyclerView.post(new Runnable() {            @Override            public void run() {                pageScrolled();            }        });    }

ScalableCardItemDecoration用于计算itemView左右剩余空间,然后为第一个itemView与最后一个itemView添加偏移量。

private static class ScalableCardItemDecoration extends RecyclerView.ItemDecoration {        @Override        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {            RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);            int position = holder.getAdapterPosition() == RecyclerView.NO_POSITION ? holder.getOldPosition() : holder.getAdapterPosition();            RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();            int itemCount = layoutManager.getItemCount();            if(position != 0 && position != itemCount - 1){                return;            }            int peekWidth = getPeekWidth(parent, view);            boolean isVertical = layoutManager.canScrollVertically();            //移除item时adapter position为-1。            if (isVertical) {                if (position == 0) {                    outRect.set(0, peekWidth, 0, 0);                } else if (position == itemCount - 1) {                    outRect.set(0, 0, 0, peekWidth);                } else {                    outRect.set(0, 0, 0, 0);                }            } else {                if (position == 0) {                    outRect.set(peekWidth, 0, 0, 0);                } else if (position == itemCount - 1) {                    outRect.set(0, 0, peekWidth, 0);                } else {                    outRect.set(0, 0, 0, 0);                }            }        }    }

在为item添加ItemDecoration时,需要计算两边的空间。这里需要手动测量itemView的宽高, 然后计算第一个itemView左边的偏移与最后一个itemView右边的偏移。这里碰到个问题,如果LayoutMangaer的方面是垂直或水平的且RecyclerView对应的的高度或宽度设为wrap_content时,这里计算的值不会正确。

public static int getPeekWidth(RecyclerView recyclerView, View itemView) {        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();        boolean isVertical = layoutManager.canScrollVertically();        int position = recyclerView.getChildAdapterPosition(itemView);        //TODO RecyclerView使用wrap_content时,获取的宽度可能会是0。        int parentWidth = recyclerView.getMeasuredWidth();        int parentHeight = recyclerView.getMeasuredHeight(); //有时会拿到0        parentWidth = parentWidth == 0 ? recyclerView.getWidth() : parentWidth;        parentHeight = parentHeight == 0 ? recyclerView.getHeight() : parentHeight;        int parentEnd = isVertical ? parentHeight : parentWidth;        int parentCenter = parentEnd / 2;        int itemSize = isVertical ? itemView.getMeasuredHeight() : itemView.getMeasuredWidth();        if (itemSize == 0) {            ViewGroup.LayoutParams layoutParams = itemView.getLayoutParams();            int widthMeasureSpec =                    RecyclerView.LayoutManager.getChildMeasureSpec(parentWidth,                            layoutManager.getWidthMode(),                            recyclerView.getPaddingLeft() + recyclerView.getPaddingRight(),                            layoutParams.width, layoutManager.canScrollHorizontally());            int heightMeasureSpec =                    RecyclerView.LayoutManager.getChildMeasureSpec(parentHeight,                            layoutManager.getHeightMode(),                            recyclerView.getPaddingTop() + recyclerView.getPaddingBottom(),                            layoutParams.height, layoutManager.canScrollVertically());            itemView.measure(widthMeasureSpec, heightMeasureSpec);            itemSize = isVertical ? itemView.getMeasuredHeight() : itemView.getMeasuredWidth();        }        /*            计算ItemDecoration的大小,确保插入的大小正好使view的start + itemSize / 2等于parentCenter。         */        int startOffset = parentCenter - itemSize / 2;        int endOffset = parentEnd - (startOffset + itemSize);        return position == 0 ? startOffset : endOffset;    }

添加完ItemDecoration后,我们需要在RecyclerView每次滚动的时候计算左、中、右3个itemView的缩放比例。

private void pageScrolled() {        if (recyclerView == null || recyclerView.getChildCount() == 0)            return;        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();        View snapingView = snapHelper.findSnapView(layoutManager);        int snapingViewPosition = recyclerView.getChildAdapterPosition(snapingView);        View leftSnapingView = layoutManager.findViewByPosition(snapingViewPosition - 1);        View rightSnapingView = layoutManager.findViewByPosition(snapingViewPosition + 1);        float leftSnapingOffset = calculateOffset(recyclerView, leftSnapingView);        float rightSnapingOffset = calculateOffset(recyclerView, rightSnapingView);        float currentSnapingOffset = calculateOffset(recyclerView, snapingView);        if (snapingView != null) {            snapingView.setScaleX(currentSnapingOffset);            snapingView.setScaleY(currentSnapingOffset);        }        if (leftSnapingView != null) {            leftSnapingView.setScaleX(leftSnapingOffset);            leftSnapingView.setScaleY(leftSnapingOffset);        }        if (rightSnapingView != null) {            rightSnapingView.setScaleX(rightSnapingOffset);            rightSnapingView.setScaleY(rightSnapingOffset);        }        if(snapingView != null && currentSnapingOffset >= 1){            OnPageChangeListener listener = pageChangeListenerRef != null ? pageChangeListenerRef.get(): null;            if(listener != null)                listener.onPageSelected(snapingViewPosition);        }        Log.d(TAG, String.format("left: %f, right: %f, current: %f", leftSnapingOffset, rightSnapingOffset, currentSnapingOffset));    }

计算缩放比例时是根据左、中、右三个itemView的中间点与RecyclerView中间点的距离来计算的。

private float calculateOffset(RecyclerView recyclerView, View view) {        if (view == null)            return -1;        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();        boolean isVertical = layoutManager.canScrollVertically();        int viewStart = isVertical ? view.getTop() : view.getLeft();        int viewEnd = isVertical ? view.getBottom() : view.getRight();        int centerX = isVertical ? recyclerView.getHeight() / 2 : recyclerView.getWidth() / 2;        int childCenter = (viewStart + viewEnd) / 2;        int distance =   Math.abs(childCenter - centerX);        if (distance > centerX)            return STAY_SCALE;        float offset = 1.f - (distance / (float) centerX);        return (1.f - STAY_SCALE) * offset + STAY_SCALE;    }

项目地址: https://github.com/yjwfn/recyclerview-gallery

转载于:https://www.cnblogs.com/xwgblog/p/7580812.html

你可能感兴趣的文章
泰勒展开,傅里叶变换,拉普拉斯变换和Z变换的物理意义
查看>>
Java Concurrentmodificationexception异常原因和解决方法
查看>>
Python 面向对象(其四)
查看>>
客户端访问浏览器的流程
查看>>
Linux——ls
查看>>
操作系统(八) 死锁
查看>>
codeforces水题100道 第二十二题 Codeforces Beta Round #89 (Div. 2) A. String Task (strings)
查看>>
c++||template
查看>>
[BZOJ 5323][Jxoi2018]游戏
查看>>
编程面试的10大算法概念汇总
查看>>
Vue
查看>>
表变量与临时表的优缺点(转)
查看>>
shell脚本图书
查看>>
UNIX环境高级编程——线程限制
查看>>
UNIX网络编程——原始套接字SOCK_RAW
查看>>
TCP发送源码学习(1)--tcp_sendmsg
查看>>
使用两个不同类型的数据进行加法计算时,使用异常处理语句捕获由于数据类型错误而出现的异常,发生生成错误。是否继续并运行上次的成功生成?...
查看>>
python-三级菜单和购物车程序
查看>>
web开发灵感推荐--34个有吸引力的电影网站设计灵感
查看>>
sql操作
查看>>