带视差滚动头部的RecyclerView

作者: PandaQ404 | 来源:发表于2016-09-22 11:41 被阅读1310次

    talk is cheap show me the pictures!

    LinearlayoutmanagerLinearlayoutmanager

    另外两种布局与LinearlayoutManager类似,头部布局独占一行,正常item跟平时使用的recyclerView一致

    sample

    demo目录

    enter description hereenter description here

    values目录下的attrs中添加资源

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="MyRecyclerView">
            <attr name="layout" format="reference"/>
            <attr name="parallaxMultiplier" format="float"/>
        </declare-styleable>
    </resources>
    

    使用布局文件中引入控件

        <com.pandaq.collapsingheaderrecyclerview.myrecyclerview.MyRecyclerView
            android:id="@+id/myrecycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout="@layout/recycler_header"
            app:parallaxMultiplier="0.8"/>
    

    layout对应的是头部视图的布局文件
    parallaxMultiplier是滑动视差因子默认值是1

    使用时写一个继承自BaseRecyclerAdapter类的方法并重写其中的必要方法onCreateonBaind

    class RecyclerAdapter extends BaseRecyclerAdapter<String> {
    
        private Context mContext;
    
        RecyclerAdapter(Context context) {
            mContext = context;
        }
    
        @Override
        public RecyclerView.ViewHolder onCreate(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_item, parent, false);
            return new ViewHolder(view);
        }
    
        @Override
        public void onBind(RecyclerView.ViewHolder viewHolder, int RealPosition, String data) {
            ViewHolder holder = (ViewHolder) viewHolder;
            holder.mText.setText(data);
        }
    
         private class ViewHolder extends BaseRecyclerAdapter.Holder {
            @BindView(R.id.text)
            TextView mText;
            ViewHolder(View view) {
                super(view);
                ButterKnife.bind(this, view);
            }
        }
    }
    

    使用recyclerView的地方与普通recyclerview一样,设置布局,为适配器添加数据,设置适配器

        mMyrecycler.setLayoutManager(new LinearLayoutManager(this));
    
        adapter.addDatas(dataList);
        mMyrecycler.setAdapter(adapter);
    

    实现

    头部视图的滑动视差效果是通过滑动的时候不断设置更新头部的底部margin来实现的即MyrecyclerView类中的onScrolled方法的这段代码

        //当添加了头部视图且当前头部视图可见的时候给头部视图添加滚动视差效果
        if (headerView != null&&firstVisibleItemPosition == 0) {
            if (distance <= headerView.getHeight()) {                       
                distance = dy;
            } else {
                distance = headerView.getHeight();
            }            
            LayoutParams layoutParams = (LayoutParams) headerView.getLayoutParams();
            //重新赋值给底部边距
            scrolledMargin = -distance + scrolledMargin;
            if (scrolledMargin > 0) {
                scrolledMargin = 0;
            }
            layoutParams.setMargins(0, 0, 0, (int) (multiplier * scrolledMargin));
            headerView.setLayoutParams(layoutParams);
        }
    

    其中的firstVisibleItemPosition的值 LinearLayoutManagerGridLayoutManager可用findFirstVisibleItemPosition()方法获取。(PS:findLastVisibleItemPosition()可以获取最后一个item的position。可以用这两个方法来判断是否滑动到底部或顶部,滑动是否进行加载或刷新)

    StaggeredFridLayoutManager则只有findLastVisibleItemPositions(int []positions)findFirstVisibleItemPositions(int[]positions)方法。这两个方法会将每一页显示的第一个或者最后一个item的position放置到传入的数组中。取出数组中的最大最小值则是整个recyclerView的最后一个或者第一个Item的位置

    布局兼容

    如果不对Adapter进行任何处理像正常使用recyclerView一样使用会发现除了LinearLayoutManager布局会正常显示其他两种方式头部视图都是占一个item的位置而不是一整行。对于这个问题我在这儿找到了答案

    通过构建一个继承自RecyclerView.Adapter<RecyclerView.ViewHolder>的抽象类BaseRecyclerAdapter<T>重写其中的onAttachedToRecyclerView(RecyclerView recyclerView)方法和onViewAttachedToWindow(RecyclerView.ViewHolder holder)方法来实现头部视图独占一行。使用Adapter的时候直接继承这个类就好了。

        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
    
            RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
            if (manager instanceof GridLayoutManager) {
                final GridLayoutManager gridManager = ((GridLayoutManager) manager);
                gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        return getItemViewType(position) == TYPE_HEADER
                                ? gridManager.getSpanCount() : 1;
                    }
                });
            }
        }
    
        @Override
        public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
            super.onViewAttachedToWindow(holder);
            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
            if (lp != null
                    && lp instanceof StaggeredGridLayoutManager.LayoutParams
                    && holder.getLayoutPosition() == 0) {
                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
                p.setFullSpan(true);
            }
        }
    

    HeaderView

    headerView使用也很简单,MyRecyclerView中构造了一个getHeaderView()方法。该方法会返回一个View对象,获取到这个对象之后想怎么处理就随便你自己发挥了。我正在写的这个项目中headerView就是一个顶部的ViewPager实现的轮播Bander,目前还没有发现什么不良反应。

    最后贴上demo下载地址

    相关文章

      网友评论

      • hewking:大佬 demo ,看不到了,有新地址吗
      • b83e3919f371:这个要是添加tablayout,在划动时把tablayout的位置固定在页面顶部怎么弄,类似斗鱼鱼吧
        PandaQ404:@乃_34d3 这个实际整体是个recyclerview,把tablayout放头部是做不到悬浮效果的,你可以尝试把tablayout放在这个控件的上层

      本文标题:带视差滚动头部的RecyclerView

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