美文网首页Material Design 学习技术recyclerView
自定义RecyclerView添加HeaderView,添加Fo

自定义RecyclerView添加HeaderView,添加Fo

作者: 菜鸟_一枚 | 来源:发表于2016-09-25 16:49 被阅读1459次

    显示效果图

    同步更新CSDN

    http://blog.csdn.net/wuyinlei/article/details/52662960

    PS

    接触过RecyclerView的应该会有个感觉,那就是我不想在使用ListView和GridView了,因为这个控件是可以实现那两个控件(ListView和GridView)所实现的几乎所有吧,哈哈我也没用他们俩干过多少的变种哈。所以在新项目中
    自然也要使用这个RecyclerView来实现效果啊。

    产品要求

    头部可以任意定义的,比如说Banner图轮播,各种列表显示,几种分类,然后滑动到底部(RecyclerView)显示加载更多提示,然后子线程请求数据,进行数据加载,更新UI,如果没有数据,就给一个友好的用户提示。

    刚开始想法

    因为这个看起来很好办的,整个放到一个ScrollView里面,这样可以实现整体可以滑动,然后监听ScrollView滑动到底部的事件,然后去请求数据,但是我自己实现过一次,效果是可以了,但是滑动起来是有阻尼的(感觉啊),滑动不过2-3个item就会停止,感觉虽然效果实现了,但是用户体验却不怎么好,(PS:还没找到为啥有阻尼,可能自己使用了一个RelativeLayout的(实现上拉加载更多监听和下拉刷新监听的自定义类吧)),有空去自己看下原因吧。

    去实现

    说实话,对于RecyclerView自己还是了解一些的,也写过一些简单的介绍,之前也自己实现了一个下拉加载更多的提交到的了git,大家可以去参考下。(小弟功底有限,还请多多包涵https://github.com/wuyinlei/RecycleViewRefreshDemo),那么今天这个实现的上拉加载更多也是按照这个思路去实现的,就是通过监听RecyclerView滑动到底部的方法来判断是否要显示底布局,然后去加载数据。

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override 
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                } 
     
                @Override 
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    //是否是最后一个显示的item位置
                    int lastVisiableItemPosition = manager.findLastVisibleItemPosition();
                    if (lastVisiableItemPosition + 1 == mCategoryAdapter.getItemCount()){
                        if (!isLoading){
                            isLoading = true;  //标志位  防止重复加载数据
                            handler.postDelayed(new Runnable() {
                                @Override 
                                public void run() { 
                                    //requestData(); 
                                    requestLoadMoreData();   //请求数据
                                    //    Toast.makeText(MainActivity.this, "已经没有新的了", Toast.LENGTH_SHORT).show(); 
                                    isLoading = false;  //加载完成数据   更新标志位
                                    // adapter.notifyItemRemoved(adapter.getItemCount()); 
                                } 
                            },2000); 
                        } 
                    } 
                } 
            }); 
    
     private void requestLoadMoreData(){ 
     
            index++;  //这个是模拟加载几次之后通知没有数据的
     
            if (index <= 3) {
                initData(); 
            } else { 
                Toast.makeText(MainActivity.this, "已经没有新的了", Toast.LENGTH_SHORT).show();
            } 
            // swipeRefreshLayout.setRefreshing(false); 
            mCategoryAdapter.notifyItemRemoved(mCategoryAdapter.getItemCount());  //加载完成之后移除footerView,也就是隐藏(去除加载中的view)
     
        } 
     
    

    这样就可以很简单的实现上拉加载更多的逻辑实现了,(这个需要添加一个footerView,接下来就来分析一下如果添加FooterView,还有就是添加HeaderView)

    Adapter如果写

    首先定义三个变量用来说明是哪一个View,(HeaderView、View、FooterView)

        public static final int TYPE_HEADER = 0;
        public static final int TYPE_NORMAL = 1;
        private static final int TYPE_FOOTER = 2;
    
    RecyclerView提供个getItemViewType(int position)方法来判断需要展示的哪种类型的View
            if (mHeaderView == null) return TYPE_NORMAL;
            if (position == 0) return TYPE_HEADER;
            if (mHeaderView != null && position +1 == getItemCount()) return TYPE_FOOTER;
            if (mHeaderView == null && position  == getItemCount()) return TYPE_FOOTER;
            return TYPE_NORMAL;
    

    对于FooterView和HeaderView我们可以共用同一个ViewHolder(其实也就是使用一下,对于HeaderView的点击事件我们是在Activity或者Fragment里面去写的,后面有介绍)。这个时候我们在绑定ViewHolder的时候去判断我们需要展示的哪种View

      @Override 
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (mHeaderView != null && viewType == TYPE_HEADER) return new ViewHolder(mHeaderView);
            if (viewType == TYPE_FOOTER) {
                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_foot, parent, false);
                return new FooterViewHolder(view);
            } 
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.category_item_layout, parent, false);
            return new ViewHolder(view);
        } 
    
    对于正常View的ViewHolder也是正常的写,按照之前的正常使用RecyclerView的方式。例如:
    class ViewHolder extends RecyclerView.ViewHolder { 
     
            private LinearLayout mCategoryLl;
            private ImageView mCategoryImg;
            private TextView mCategoryTitle, mCategoryDes;
     
            public ViewHolder(View itemView) {
                super(itemView);
                mCategoryImg = (ImageView) itemView.findViewById(R.id.category_book_img);
                mCategoryTitle = (TextView) itemView.findViewById(R.id.category_title);
                mCategoryDes = (TextView) itemView.findViewById(R.id.category_book_des);
                mCategoryLl = (LinearLayout) itemView.findViewById(R.id.category_ll);
            } 
        } 
    
    对于HeaderView,我们的处理方式(在Adapter里面进行)
    public void setHeaderView(View headerView) {
            mHeaderView = headerView;
            notifyItemInserted(0);   //位于顶部,通知一下view的第一项
        } 
    
    这个时候通过在activity或者fragment里面进行
     private void setHeader(RecyclerView view) {
            //找到控件布局
            View header = LayoutInflater.from(this).inflate(R.layout.category_item_header, view, false);
     
            mRlBoy = (RelativeLayout) header.findViewById(R.id.rl_boy);
            mRlGirl = (RelativeLayout) header.findViewById(R.id.rl_girl);
            mRlEnd = (RelativeLayout) header.findViewById(R.id.rl_end);
            mRlUpdate = (RelativeLayout) header.findViewById(R.id.rl_update);
     
            mCategoryAdapter.setHeaderView(header); //设置headerview
        } 
    
    HeaderView控件监听方式可以如下:
      private void initListener() { 
            mRlBoy.setOnClickListener(this);
            mRlGirl.setOnClickListener(this);
            mRlEnd.setOnClickListener(this);
            mRlUpdate.setOnClickListener(this);
        } 
    

    基本到此为止,就能实现一般的需求了,如果有复杂的,应该还是存在其他方式的实现,以后有空或者有此需求之后自己在去研究。

    解决在GridView形式下,HeaderView和FooterView只显示在最前面一个或者最后面一个(而不是占据一行bug)
     final GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
            gridLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
            mRecyclerView.setLayoutManager(gridLayoutManager);
    
            // gridLayoutManager  布局管理器
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    //如果是第一个(添加HeaderView)   还有就是最后一个(FooterView)
                    return position == mCategoryBean.size() + 1 || position == 0 ? gridLayoutManager.getSpanCount() : 1;
                }
            });
    
    
    效果如开始哈,在次就贴下代码吧。

    代码传动门:demo地址

    相关文章

      网友评论

      • 76ffef5441ab:厉害了我哥
      • a97e43ac9d02:我添加FooterView ,recyclerview是一个2列的girdview样式,为什么footerview总是在最后一个item后面?没有在2个item中间位置
        菜鸟_一枚:@未知先生 你好,感谢提问,这个之前没试过,刚刚试了一下,确实出现了描述的问题,可以写入以下的代码来计算header或者footer宽度占据一整行,已经测试可以实现。
        // gridLayoutManager 布局管理器
        gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
        @Override
        public int getSpanSize(int position) {
        //如果是第一个(添加HeaderView) 还有就是最后一个(FooterView)
        return position == mCategoryBean.size() + 1 || position == 0 ? gridLayoutManager.getSpanCount() : 1;
        }
        });
        可以参考一下http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0722/3214.html :joy:

      本文标题:自定义RecyclerView添加HeaderView,添加Fo

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