美文网首页Android开发viewAndroid developing tips
使用RecyclerView实现Gallery画廊效果

使用RecyclerView实现Gallery画廊效果

作者: 依然fantac | 来源:发表于2016-09-02 16:24 被阅读14265次

先贴图


要实现上面的画廊效果,传统通过ViewPager clipChildren置为false实现。网上很多教程这个不多说,现在说说用RecyclerView实现上面的效果。这个效果分两步:

  1. ViewPager滑动最终居中停止
  2. 滑动过程中缩放

ViewPager滑动最终居中停止

Support RecyclerView 24.2.0中增加一个非常重要的类SnapHelper,他的作用是让RecyclerView滑动视图后使停止位置正好停在某页的正中间。使用方式很简单
重点在于new LinearSnapHelper().attachToRecyclerView(recyclerView);

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(linearLayoutManager);

new LinearSnapHelper().attachToRecyclerView(recyclerView);

一行代码搞定居中,LinearSnapHelper的源码解析查看这里

滑动过程中缩放

毫无疑问,RecyclerView的滑动缩放必须要监听RecyclerView的滑动

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        // dx>0则表示右滑, dx<0表示左滑, dy<0表示上滑, dy>0表示下滑
        mCurrentItemOffset += dx;
        computeCurrentItemPos();
        onScrolledChangedCallback();
    }
});     

mCurrentItemOffset为滑动总距离,Card每页滑动的距离是固定的,根据这个可以计算出当前显示的位置。缩放看onScrolledChangedCallback这个函数,有了滑动位置就能实时计算滑动某页的百分比
float percent = (float) Math.max(Math.abs(offset) * 1.0 / mOnePageWidth, 0.0001);

得到百分比, 再获取当前位置相邻的视图调用setScaleY函数实现缩放

/**
 * RecyclerView位移事件监听, view大小随位移事件变化
 */
private void onScrolledChangedCallback() {
    int offset = mCurrentItemOffset - mCurrentItemPos * mOnePageWidth;
    float percent = (float) Math.max(Math.abs(offset) * 1.0 / mOnePageWidth, 0.0001);
    
    View leftView = null;
    View currentView;
    View rightView = null;
    if (mCurrentItemPos > 0) {
        leftView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos - 1);
    }
    currentView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos);
    if (mCurrentItemPos < mRecyclerView.getAdapter().getItemCount() - 1) {
        rightView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos + 1);
    }

    if (leftView != null) {
        // y = (1 - mScale)x + mScale
        leftView.setScaleY((1 - mScale) * percent + mScale);
    }
    if (currentView != null) {
        // y = (mScale - 1)x + 1
        currentView.setScaleY((mScale - 1) * percent + 1);
    }
    if (rightView != null) {
        // y = (1 - mScale)x + mScale
        rightView.setScaleY((1 - mScale) * percent + mScale);
    }
}

完整代码下载

https://github.com/huazhiyuan2008/RecyclerViewCardGallery

相关文章

网友评论

  • 为自己代颜_:item之前的间距如何设置呢?请教一下~~~~
  • 为自己代颜_:请问如何实现循环滑动呢?谢谢。
  • 73ece15c815f:左右有个回弹效果是哪里来的呀,哪里关闭呀
  • _Anonymouz:可以实现停靠在左边位置,同时显示第二条item的一半这种效果吗?
  • dde82929c761:怎么修改两个item间的距离
  • 00dd53b462be:最后一个Item怎么不管点击?
  • dc0a78649aad:为什么每滑动一次两侧都闪一下才缩小 怎么解决?
    詠遠鍀飛哥:private void computeCurrentItemPos() {
    if (mOnePageWidth <= 0) return;
    boolean pageChanged = false;
    // 滑动超过一页说明已翻页
    if (Math.abs(mCurrentItemOffset - mCurrentItemPos * mOnePageWidth) >= mOnePageWidth) {
    pageChanged = true;
    }
    // if (pageChanged) {
    int tempPos = mCurrentItemPos;
    int offset = 0;
    if(mCurrentItemOffset % mOnePageWidth > 0.5 * mOnePageWidth){
    offset += 1;
    }
    mCurrentItemPos = mCurrentItemOffset / mOnePageWidth + offset;
    DebugLog.i(String.format("=======onCurrentItemPos Changed======= tempPos=%s, mCurrentItemPos=%s", tempPos, mCurrentItemPos));
    // }
    }
  • c131881addc9:获取当前项的position有问题:mCardScaleHelper.getCurrentItemPos();
    买辣条也想用券:private void computeCurrentItemPos() {
    if (mOnePageWidth <= 0) return;
    boolean pageChanged = false;
    //滑动超过一页说明已翻页
    if (Math.abs(mCurrentItemOffset - mCurrentItemPos * mOnePageWidth) >= mOnePageWidth) {
    pageChanged = true;
    }
    int tempPos = mCurrentItemPos;
    int offset = 0;
    if (mCurrentItemOffset % mOnePageWidth > 0.5 * mOnePageWidth) {
    offset += 1;
    }
    mCurrentItemPos = mCurrentItemOffset / mOnePageWidth + offset;
    }
  • CokeNello:楼主,貌似我设置了Item的宽带不起作用,Demo中设置也是如此。Item的宽度不变。
  • 谁明熊哥心:代码在activity 没有问题,但在fragment上会崩溃,真机与虚拟机也有区别
  • 92672fc4cb30:亲,我发现你这个如果刷新数据的话,item会出现问题,不知道怎么解决。。。。
  • 26d7895fa345:大神你好 图片如果是网络请求过来的 怎么办 ,请求过来是图片的url 而不是图片 ,
    a3c38ba94b24:楼主您好~~~ 我有两个小问题,一个是高斯模糊的背景图如果是从网络加载获取的如何将它放入进去,改了改好像没效果~~。然后还有就是定位的问题 怎么设置定位呢 或者说快速定位呢 谢谢大神啦
    依然fantac:@cv小法师 网络图片不是一样的么, 加个默认图片
  • bf5901521ca3:先赞一个!:+1:
    请教下:如果调整卡边两边的距离宽度?我设置了setPagePadding 和 setShowLeftCardWidth
    但好像没有起作用
  • 黄油奥利奥:作者6666666666
  • 建木晷天:怎么可以一排显示多个,我试了试改了没用
  • c3f1ada035f0:请问垂直的效果要怎么去实现
  • Mr_Tu:楼主,ScreenUtil这个工具类木有啊~
  • kylodw:左右两边的view能不能实现倾斜,我不太会。
    b6f561235d67:请问你实现倾斜了吗
  • kizi:有一个位置很奇怪,我按照你的项目敲,发现,你给的三张图其中有两张因为是300kb左右,让效果看起来非常卡顿。后来换成57kb的那张就好多了。但是,把你的demo跑了一遍,发现很流畅。不解~
    泡泡secret:@kizi 我的也很卡顿,你是怎么改的呢?
    kizi:@依然fantac 找到原因了,属于多分辨率适配的问题,已经解决
    依然fantac:是不是在主线程做了耗时操作
  • 5860bd069620:为何最后一项Item点击无效
  • a3f4fdbfbb5e:请问这个对item的布局有什么要求么 为什么我item写出来都是占一屏 左右看不见item
    CokeNello:@阿祥大宝贝 :joy: 回想一下?给点思路
    a3f4fdbfbb5e:@栗子酱油饼 这个好久了 我都忘了:joy:
    CokeNello:你好,我也跟你遇到同样的问题,请问你解决了吗?
  • huangyirui: 请问 recycleview 要是垂直的 怎么实现这种效果额?
  • 24e2d9528488:我想让两边的图片显示宽一点,好像设置没效果哦
  • 小千聊安卓:代码不全, 有两个工具类没有放出
    小千聊安卓:@依然fantac 就是从github下的代码, 缺乏两个工具类
    依然fantac:@ChewlyHorser 相关源码都在github上
  • ee89ff506c7f:删除添加某些数据或者更换数据源后,效果就没了。有解决办法吗?
  • 24cb49cd798a:定位怎么实现快速定位呢 直接用scrollToPosition貌似无效
  • 学子要远行:效果很棒,不过是我有个需求,实现那种驾校一点通的题库 左右切换更换题目,几千道题目,需要网络加载,那么item好像不能满足,需要是fragment。。这个应该怎么办
    学子要远行: @依然fantac 嗯嗯,好的谢谢啦,这个能支持每次滑动一页吗😗😗
    依然fantac:@学子要远行 view进行网络请求,recyclerView有回收机制,几千条不是问题
  • 51f82b05f43f:能像Gallery一样,第一个和最后一个item都显示在中间,前面和后面留白吗?
    依然fantac:@brucewuu 可以的,原理一样
  • 断金岁月:各位朋友 我怎么找不到v4的24版本啊 都是23的 我在studio中搜索的
  • 整天做梦:划动动画有点问题,手指划动速度如果不快的话,有时候会突然间跳到中间,很不舒服,期待修复
  • 85220324c87c:能不能把每个显示的界面,写成fragment或者activity的??作者。
    想每个页面都能进行网络请求。
    依然fantac:@85220324c87c RecyclerView的item只能是View。可以考虑根据recyclerView的position控制View的网络请求
  • 捡淑:66666
  • 静静De欧巴:太赞了!!!!
  • Clendy:非常不错~~ 收藏了
  • dcd36a030648:效果太棒了

本文标题:使用RecyclerView实现Gallery画廊效果

本文链接:https://www.haomeiwen.com/subject/kkxkettx.html