美文网首页Androidandroid开发资料 | 汇总
给 RecyclerView 加上折叠的效果

给 RecyclerView 加上折叠的效果

作者: NanBox | 来源:发表于2017-02-18 13:39 被阅读4847次

    RecyclerView 有很高的自由度,可以说只有想不到没有做不到,真是越用越喜欢。这次用超简单的方法,让 RecyclerView 带上折叠的效果。

    效果是这样的。

    总结一下这个列表的特点,就是以下三点:

    1. 重叠效果;
    2. 层次感;
    3. 首项的差动。

    下面我们来一个个解决。

    我们新建一个 ParallaxRecyclerView,让它继承 RecyclerView,并使用 LinearLayoutManager 作为布局管理器。

    重叠效果

    其实就是每一项都搭一部分在它前面那项而已。我们知道,RecyclerView 可以通过设置 ItemDecoration 来实现列表的间隔效果,有没有想过要是把间隔设为负数会怎么样?比如:

    addItemDecoration(new ItemDecoration() {
                @Override
                public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
                    super.getItemOffsets(outRect, view, parent, state);
                    outRect.bottom = -dp2px(context, 10);
                }
            });
    

    没错,这就实现了我们的重叠效果。

    层次感

    在 Material Design 里是有Z轴这个概念的,我们可以给控件设置垂直于屏幕的高度,让不在同一高度的控件看起来有层次感。当然,我们要用 Material Design 的控件才有这个属性,这里我用的是 CardView。

    我们给 ParallaxRecyclerView 增加一个滑动监听,在 onScrolled 方法里面做如下设置:

    LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
    int firstPosition = layoutManager.findFirstVisibleItemPosition();
    int lastPosition = layoutManager.findLastVisibleItemPosition();
    int visibleCount = lastPosition - firstPosition;
    //重置控件的高度
    int elevation = 1;
    for (int i = firstPosition - 1; i <= (firstPosition + visibleCount) + 1; i++) {
        View view = layoutManager.findViewByPosition(i);
        if (view != null) {
            if (view instanceof CardView) {
                ((CardView) view).setCardElevation(dp2px(context, elevation));
                elevation += 5;
            }
           
        }
    }
    

    其中,setCardElevation 方法就是用来给 CardView 设置高度的,这里让每一项的高度比它的上一项高 5dp。

    首项的差动

    最后,我们想给第一项增加一个差动效果,这个同样在 onScrolled 方法里面做处理就好了:

    View firstView = layoutManager.findViewByPosition(firstPosition);
    float firstViewTop = firstView.getTop();
    firstView.setTranslationY(-firstViewTop / 2.0f);
    

    这样相当于第一项的滑动速度变成原来的一半。但这也会导致一个问题, 由于改变了控件的位置,当这个控件被复用时,会出现位置不正确的情况。所以我们在设置高度的时候,可以顺便把控件的位置复原了:

     float translationY = view.getTranslationY();
    if (i > firstPosition && translationY != 0) {
        view.setTranslationY(0);
    }
    

    这样就完成了一个带有简单折叠效果的 RecyclerView 了,妥妥的。

    源码地址

    相关文章

      网友评论

      • Coder_熊哥哥:博主 怎么实现那种 近大远小的效果呢 最顶上最大 下边越来越小
      • 懂懂_310a:最后一项没有显示完全,怎么破
        f3fe33ea0f80:仔细看了,先下滑,然后上滑,int firstPosition = layoutManager.findFirstVisibleItemPosition();,firstPosition位置的view要完全显示出来,firstPosition的前一个view才会出来,firstPosition位置的view上圆角那里会突然弹出上面的view
        NanBox: 感谢你的反馈!这个问题已经修复,在设置间隔的时候,增加了是否为最后一项的判断:

        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
        super.getItemOffsets(outRect, view, parent, state);
        //获取当前项的下标
        final int currentPosition = parent.getChildLayoutPosition(view);
        //获取最后一项的下标
        final int lastPosition = state.getItemCount() - 1;
        if (currentPosition != lastPosition) {
        outRect.bottom = -dp2px(context, 10);
        }
        }
      • Shur:帅了
      • Cyandev:可以试图把下边的圆角去掉,这样能达到 iOS Wallet 里的效果。
      • 0362bb07dd8d:想法不错
      • Tonlin:写的真好!
        NanBox: @Tonlin 谢谢!
      • xyzsyy0102:厉害了我的哥
      • 努力生活的西鱼:你录屏怎么录的?
        NanBox:用Android Studio录屏之后,再用LICEcap录成GIF
      • Avalon1:但是在api 21以下没有elevation,那不是没法了
        NanBox:在api 21以下也可以用elevation,但是没有层次的效果,只有一条分割线。
      • 千渊载明:圆角看起来好别扭啊前辈
        NanBox: @拾光浅唱 好像是有点😂

      本文标题:给 RecyclerView 加上折叠的效果

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