美文网首页Android开发Android进阶之路Android技术知识
RecyclerView系列之五:添加Header和Footer

RecyclerView系列之五:添加Header和Footer

作者: 滴滴滴9527 | 来源:发表于2017-04-26 20:18 被阅读0次
    一、核心思想

    根据AdaptergetItemViewType( )返回结果的不同来返回我们的item数量ViewHolder.

    二、代码
    (1)MainActivity布局文件
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerview"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
    
    </LinearLayout>
    
    (2)item布局文件
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:background="#ff33b5e5"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:gravity="center"
            tools:text="别看了,我就是一个TextView" />
    </RelativeLayout>
    
    (3)Header和Footer的布局文件
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:background="@android:color/holo_orange_light"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:gravity="center"
            android:text="我是头布局" />
    
    </RelativeLayout>
    
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:background="@android:color/holo_orange_light"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:gravity="center"
            android:text="我是脚布局" />
    </RelativeLayout>
    
    (4)MainActivity中
    public class MainActivity extends AppCompatActivity {
    
        private RecyclerView mRecyclerView;
        private MainAdapter mAdapter;
        private List<String> mDatas;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initData();
            mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
            mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
            mAdapter = new MainAdapter(this,mDatas);
            mRecyclerView.setAdapter(mAdapter);
    
            //添加Header和Footer
            addHeader();
            addFooter();
        }
    
        private void addHeader() {
            View v = LayoutInflater.from(this).inflate(R.layout.item_header, mRecyclerView, false);
            mAdapter.setHeaderView(v);
        }
    
        private void addFooter() {
            View v = LayoutInflater.from(this).inflate(R.layout.item_footer, mRecyclerView, false);
            mAdapter.setFooterView(v);
        }
    
    
        private void initData() {
            mDatas = new ArrayList<>();
                for (int i = 'A'; i < 'Z'; i++) {
                mDatas.add("" + (char) i);
            }
        }
    }
    
    (6)MainAdapter 中
    public class MainAdapter extends RecyclerView.Adapter<MainAdapter.MyViewHolder> {
    
        private Context mContext;
        private List<String> mDatas;
    
        //定义三种类型来对应我们的Header、正常布局、Footer
        public static final int TYPE_HEADER = 0;
        public static final int TYPE_NORMAL = 1;
        public static final int TYPE_FOOTER = 2;
    
        private View mHeaderView;
        private View mFooterView;
    
        public MainAdapter(Context context, List<String> mDatas) {
            this.mContext = context;
            this.mDatas = mDatas;
        }
    
        public void setHeaderView(View headerView) {
            mHeaderView = headerView;
            notifyItemInserted(0);//注意这里
        }
        public View getHeaderView() {
            return mHeaderView;
        }
    
        public void setFooterView(View footerView) {
            mFooterView = footerView;
            notifyItemInserted(getItemCount()-1);//注意这里
        }
        public View getFooterView() {
            return mFooterView;
        }
    
        /**
         * 重写了getItemViewType方法,根据位置返回不同的ViewType
         */
        @Override
        public int getItemViewType(int position) {
            if (mHeaderView == null && mFooterView == null) {
                return TYPE_NORMAL;
            }
            if (position == 0) {
                return TYPE_HEADER;
            }
            if (position == getItemCount() - 1) {
                return TYPE_FOOTER;
            }
            return TYPE_NORMAL;
        }
    
        /**
         * 根据不同的ViewType返回不同的item数量
         */
        @Override
        public int getItemCount() {
            if(mHeaderView == null && mFooterView == null){
                return mDatas.size();
            }else if(mHeaderView == null && mFooterView != null){
                return mDatas.size() + 1;
            }else if (mHeaderView != null && mFooterView == null){
                return mDatas.size() + 1;
            }else {
                return mDatas.size() + 2;
            }
        }
    
        /**
         * 根据不同的ViewType创建不同的ViewHolder对象
         */
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if(mHeaderView != null && viewType == TYPE_HEADER) {
                return new MyViewHolder(mHeaderView);
            }
            if(mFooterView != null && viewType == TYPE_FOOTER){
                return new MyViewHolder(mFooterView);
            }
            return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_layout, parent, false));
        }
    
    
        @Override
        public void onBindViewHolder(MyViewHolder holder, final int position) {
            if (getItemViewType(position) == TYPE_HEADER) {
                return;
            } else if (getItemViewType(position) == TYPE_FOOTER) {
                return;
            } else if (getItemViewType(position) == TYPE_NORMAL) {
                if (mHeaderView == null) {
                    holder.tv.setText(mDatas.get(position));
                } else {
                    holder.tv.setText(mDatas.get(position - 1));
                }
            }
        }
    
    
        /**
         * 这里Header和Footer很简单,就不单独为Header和Footer创建一个ViewHolder了
         */
        class MyViewHolder extends RecyclerView.ViewHolder {
            TextView tv;
    
            public MyViewHolder(View view) {
                super(view);
                if (itemView == mHeaderView){
                    return;
                }
                if (itemView == mFooterView){
                    return;
                }
                tv = (TextView)itemView.findViewById(R.id.tv);
            }
        }
    }
    
    三、效果图
    四、GridLayoutManager添加Header和Footer

    我们在MainActivity中把LinearLayoutManager换成GridLayoutManager看一看效果

    mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));
    
    //mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
    //默认的分隔线不再适应GridLayoutManager了,这里注释掉
    

    Header和Footer竟然和普通item跑到一排了......

    此时:要用到GridLayoutManager的一个方法setSpanSizeLookup

    gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
           @Override
           public int getSpanSize(int position) {
              return 0;
          }
    });
    

    这个方法需要一个SpanSizeLookup对象,SpanSizeLookup是一个定义在GridLayoutManager中抽象类,只有一个抽象方法getSpanSize(),
    这个方法的返回值决定了我们每个position上的item占据的单元格个数.

    正常情况下每个item占据1个单元格,结合GridLayoutManager构造方法中设置的每行的个数new GridLayoutManager(this, 2), 如果当前位置是Header和Footer的话,那么该item占据2个单元格,.
    ok,了解了这个方法的话就可以来解决问题了

    在Adapter中重写onAttachedToRecyclerView()方法:

        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
    
            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
    
            if (layoutManager instanceof GridLayoutManager){
                final GridLayoutManager gridManager = ((GridLayoutManager) layoutManager);
                gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        if (getItemViewType(position) == TYPE_HEADER){
                            return gridManager.getSpanCount();
                        }else if (getItemViewType(position) == TYPE_FOOTER){
                            return gridManager.getSpanCount();
                        }else{
                            return 1;
                        }
                    }
                });
            }
        }
    

    在来看一看效果:


    ok,完美解决

    五、StaggeredGridLayoutManager添加Header和Footer

    在StaggeredGridLayoutManager中并没有像GridLayoutManager中这样的方法,这里可以通过StaggeredGridLayoutManager.LayoutParams的一个方法setFullSpan(boolean fullSpan)来设置占领全部空间.

    同样:
    在Adapter中重写onViewAttachedToWindow()方法:

        @Override
        public void onViewAttachedToWindow(MyViewHolder holder) {
            super.onViewAttachedToWindow(holder);
            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
            if( lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams ) {
                StaggeredGridLayoutManager.LayoutParams  params =(StaggeredGridLayoutManager.LayoutParams) lp;
                if(holder.getItemViewType()==TYPE_HEADER || holder.getItemViewType()==TYPE_FOOTER){
                    params.setFullSpan(true);
                }else{
                    params.setFullSpan(false);
                }
            }
        }
    

    ok,解决了.

    相关文章

      网友评论

        本文标题:RecyclerView系列之五:添加Header和Footer

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