RecyclerView添加addHeader和addFooter方法

在新版本的android系統中RecyclerView作爲ListView的優化版本,封裝了ViewHolder,這樣就可以更加方便的使用這個控件。但是相比較ListView,RecyclerView沒有提供相應的addHeaderView和addFooterView方法,我們知道在一些下拉控件的實現中,都是設置了headerView或者是footerView,然後不斷的設置padding來實現的。那既然RecyclerView沒有addHeaderView和addFooterView這些方法,那麼是不是就不能實現下拉刷新這樣的功能了呢?當然不是。下面就帶大家實現一個簡易的實現addHeaderView和addFooterView的方法。

我們知道像需要適配器的這些控件,它們的數據都是通過Adapter的提供的。那麼我們就着手改造我們的Adapter。首先我們創建一個自定義的Adapter類繼承RecyclerView.Adapter

    public class HeaderRecyclerViewAdapter extends RecyclerView.Adapter<HeaderRecyclerViewAdapter
            .HeaderViewHolder> {
       //header view type的開始值
       private final int RECYCLER_HEADER_TYPE_BASE = 0xff11;

       //footer view type的開始值
       private final int RECYCLER_FOOTER_TYPE_BASE = 0xff22;

       //header和footer的id值
       private final int RECYCLER_HEADER_FOOTER_ID = -1;

       //用來存放所有的header view的信息
       private List<FixedInfo> mHeaders = new ArrayList<>();

       //用來存放所有的footer view的信息
       private List<FixedInfo> mFooters = new ArrayList<>();

       //保存使用默認的RecyclerView.Adapter創建的adapter的值,這個值必須獲取到
       private RecyclerView.Adapter mAdapter = null;

       public HeaderRecyclerViewAdapter() {
       }

       public HeaderRecyclerViewAdapter(RecyclerView.Adapter adapter) {
          this.mAdapter = adapter;
       }

       public void setAdapter(RecyclerView.Adapter adapter) {
          this.mAdapter = adapter;
       }

我們創建一個HeaderRecyclerViewAdapter類用來包裝我們原始的RecyclerView.Adapter類,mAdpter就是對這個原始類的應用。同樣創建了兩個ArrayList用來保存我們的Headers和footers,這裏面有一個FixedInfo類,這個類是幹嘛的呢?

    //用來保存footer和headers的信息
    private class FixedInfo {
      public View view;
      public int type;
    }

這個類比較簡單,view保存我們設置的view,type用來保存我們view的type信息,可以通過type信息識別我們的header和footer。

  public void addHeader(View view) {
      FixedInfo info = new FixedInfo();
      info.view = view;
      info.type = RECYCLER_HEADER_TYPE_BASE + mHeaders.size();
      mHeaders.add(info);
    }

    public void addFooter(View view) {
      FixedInfo info = new FixedInfo();
      info.view = view;
      info.type = RECYCLER_FOOTER_TYPE_BASE + mFooters.size();
      mFooters.add(info);
    }

可以看到,每次addHeader或者是addFooter的時候,都通過一個唯一的type信息來區別這個view。

@Override
    public long getItemId(int position) {
      int headerCount = getHeaderSize();
      if (mAdapter != null && position >= headerCount) {
         int adjPosition = position - headerCount;
         return mAdapter.getItemId(adjPosition);
      }
      return RECYCLER_HEADER_FOOTER_ID;
    }

我們需要重新getItemId()方法,如果是header或者是footer的話,直接返回我們定義的特殊值 RECYCLER_HEADER_FOOTER_ID。如果是adapter中的數據則返回adapter中的相同方法。

 @Override
    public int getItemViewType(int position) {
      if (mAdapter == null) {
         throw new IllegalStateException("must have a adapter");
      }
      int headerCount = getHeaderSize();
      int adapterCount = mAdapter.getItemCount();
      if (position < headerCount) {
         return mHeaders.get(position).type;
      } else if (position >= (headerCount + adapterCount)) {
         return mFooters.get(position - headerCount - adapterCount).type;
      } else {
         int adjPosition = position - headerCount;
         return mAdapter.getItemViewType(adjPosition);
      }
    }  

getItemViewType()是我們必須重寫的方法,在這個方法中,我們會標識每一個Header和Footer的viewType。

 @Override
    public HeaderViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      if (isHeaderView(viewType)) {
         int delta = viewType - RECYCLER_HEADER_TYPE_BASE;
         View view = mHeaders.get(delta).view;
         return new HeaderViewHolder(view);
      }
      if (isFooterView(viewType)) {
         int delta = viewType - RECYCLER_FOOTER_TYPE_BASE;
         View view = mFooters.get(delta).view;
         return new HeaderViewHolder(view);
      }
      return (HeaderViewHolder) mAdapter.onCreateViewHolder(parent,viewType);
    }

    @Override
    public void onBindViewHolder(HeaderViewHolder holder, int position) {
      int headerCount = getHeaderSize();
      if (mAdapter != null && position >= headerCount) {
         int adapterCount = mAdapter.getItemCount();
         int adjPosition = position - headerCount;
         if (adjPosition >= 0 && adjPosition < adapterCount) {
            mAdapter.onBindViewHolder(holder, adjPosition);
         }
      }
    }

最主要的地方來了,在onCreateViewHolder中,我們需要判斷當前的viewType是header的還是footer的,如果是header的或者footer的,我們需要算出這個viewtype所對應的view,用這個view來返回HeaderViewHolder。而在onBindViewHolder()方法中,我們只需要定位到屬於adapter中的數據就好,然後返回對應的方法即可。完整的代碼如下:

 package com.gearmotion.app.mylibrary;

    import android.support.v7.widget.RecyclerView;
    import android.view.View;
    import android.view.ViewGroup;

    import java.util.ArrayList;
    import java.util.List;

    /**
     * Created by Charles on 2016/3/21.
     */
    public class HeaderRecyclerViewAdapter extends RecyclerView.Adapter<HeaderRecyclerViewAdapter
        .HeaderViewHolder> {
       //header view type的開始值
       private final int RECYCLER_HEADER_TYPE_BASE = 0xff11;
       //footer view type的開始值
       private final int RECYCLER_FOOTER_TYPE_BASE = 0xff22;
       //header和footer的id值
       private final int RECYCLER_HEADER_FOOTER_ID = -1;
       //用來存放所有的header view的信息
       private List<FixedInfo> mHeaders = new ArrayList<>();
       //用來存放所有的footer view的信息
       private List<FixedInfo> mFooters = new ArrayList<>();
       //保存使用默認的RecyclerView.Adapter創建的adapter的值,這個值必須獲取到
       private RecyclerView.Adapter mAdapter = null;

       public HeaderRecyclerViewAdapter() {
       }

       public HeaderRecyclerViewAdapter(RecyclerView.Adapter adapter) {
          this.mAdapter = adapter;
       }

       public void setAdapter(RecyclerView.Adapter adapter) {
          this.mAdapter = adapter;
       }

       @Override
       public HeaderViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      if (isHeaderView(viewType)) {
         int delta = viewType - RECYCLER_HEADER_TYPE_BASE;
         View view = mHeaders.get(delta).view;
         return new HeaderViewHolder(view);
      }
      if (isFooterView(viewType)) {
         int delta = viewType - RECYCLER_FOOTER_TYPE_BASE;
         View view = mFooters.get(delta).view;
         return new HeaderViewHolder(view);
      }
      return (HeaderViewHolder) mAdapter.onCreateViewHolder(parent,viewType);
     }

       @Override
       public void onBindViewHolder(HeaderViewHolder holder, int position) {
      int headerCount = getHeaderSize();
      if (mAdapter != null && position >= headerCount) {
         int adapterCount = mAdapter.getItemCount();
         int adjPosition = position - headerCount;
         if (adjPosition >= 0 && adjPosition < adapterCount) {
            mAdapter.onBindViewHolder(holder, adjPosition);
         }
      }
    }

    @Override
    public int getItemCount() {
      if (mAdapter != null) {
         return mHeaders.size() + mAdapter.getItemCount() + mFooters.size();
      } else {
         return mHeaders.size() + mFooters.size();
      }
    }

    @Override
    public int getItemViewType(int position) {
      if (mAdapter == null) {
         throw new IllegalStateException("must have a adapter");
      }
      int headerCount = getHeaderSize();
      int adapterCount = mAdapter.getItemCount();
      if (position < headerCount) {
         return mHeaders.get(position).type;
      } else if (position >= (headerCount + adapterCount)) {
         return mFooters.get(position - headerCount - adapterCount).type;
      } else {
         int adjPosition = position - headerCount;
         return mAdapter.getItemViewType(adjPosition);
      }
   }

    @Override
    public long getItemId(int position) {
      int headerCount = getHeaderSize();
      if (mAdapter != null && position >= headerCount) {
         int adjPosition = position - headerCount;
         return mAdapter.getItemId(adjPosition);
      }
      return RECYCLER_HEADER_FOOTER_ID;
    }

    public void addHeader(View view) {
      FixedInfo info = new FixedInfo();
      info.view = view;
      info.type = RECYCLER_HEADER_TYPE_BASE + mHeaders.size();
      mHeaders.add(info);
    }

    public void addFooter(View view) {
      FixedInfo info = new FixedInfo();
      info.view = view;
      info.type = RECYCLER_FOOTER_TYPE_BASE + mFooters.size();
      mFooters.add(info);
    }

    public int getHeaderSize() {
      return mHeaders.size();
    }

    public int getFooterSize() {
      return mFooters.size();
    }

    private boolean isHeaderView(int type) {
      int delta = type - RECYCLER_HEADER_TYPE_BASE;
      return delta >= 0 && delta < mHeaders.size();
    }

    private boolean isFooterView(int type) {
      int delta = type - RECYCLER_FOOTER_TYPE_BASE;
      return delta >= 0 && delta < mFooters.size();
    }

    //用來保存footer和headers的信息
    private class FixedInfo {
      public View view;
      public int type;
    }

    //自定義的viewholder
    public static class HeaderViewHolder extends RecyclerView.ViewHolder {
      public HeaderViewHolder(android.view.View itemView) {
         super(itemView);
      }
    }
    }

最後我們在使用的時候將原始創建的adapter傳遞給HeaderRecyclerViewAdapter即可。

package com.gearmotion.app.headerrecyclerviewmotion;

     import android.support.v7.app.AppCompatActivity;
     import android.os.Bundle;
     import android.support.v7.widget.LinearLayoutManager;
     import android.support.v7.widget.RecyclerView;
     import android.text.Layout;
     import android.view.Gravity;
     import android.view.LayoutInflater;
     import android.view.View;
     import android.view.ViewGroup;
     import android.widget.TextView;

    import com.gearmotion.app.mylibrary.HeaderRecyclerViewAdapter;

    public class MainActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;
    private LayoutInflater mInflater;
    private String[] mDatas = new String[]{"title1", "title2", "title3", "title4", "title5",
           "title6"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      mInflater = LayoutInflater.from(this);
      mRecyclerView = (RecyclerView) this.findViewById(R.id.recyclerview);
      mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
      CustomAdapter tmpAdapter = new CustomAdapter();
      HeaderRecyclerViewAdapter mAdapter = new HeaderRecyclerViewAdapter(tmpAdapter);
      mAdapter.addHeader(createView("head1"));
      mAdapter.addHeader(createView("head2"));
      mAdapter.addHeader(createView("head3"));
      mAdapter.addFooter(createView("foot1"));
      mAdapter.addFooter(createView("foot2"));
      mAdapter.addFooter(createView("foot3"));
      mRecyclerView.setAdapter(mAdapter);
    }

    private View createView(String title) {
      TextView tv = new TextView(this);
      tv.setText(title);
      tv.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
              70));
      tv.setGravity(Gravity.CENTER);
      return tv;
    }

    public class CustomAdapter extends RecyclerView.Adapter<CustomViewHolder> {

      @Override
      public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         View root = mInflater.inflate(R.layout.item, null);
         return new CustomViewHolder(root);
      }

      @Override
      public void onBindViewHolder(CustomViewHolder holder, int position) {
         holder.textView.setText(mDatas[position]);
      }

      @Override
      public int getItemCount() {
         return mDatas.length;
      }
    }


    public class CustomViewHolder extends HeaderRecyclerViewAdapter.HeaderViewHolder {
      public TextView textView;

      public CustomViewHolder(View itemView) {
         super(itemView);
         textView = (TextView) itemView.findViewById(R.id.itemtextview);
      }
    }
    }

結果如下:

代碼地址如下:https://github.com/summerpxy/HeaderRecyclerViewAdapter.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章