您好,登錄后才能下訂單哦!
前言
我們大家都知道ListView具有添加頭部和添加底部的方法,但是RecyclerView并沒有這樣子的方法。所以RecyclerView是不能添加底部和頭部的,但是能不能仿造ListView來實現RecyclerView添加頭部和底部呢?答案當然是可行的。本文就來給大家介紹了關于Android封裝RecyclerView添加頭部和底部的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。
首先看下實現的效果:
代碼如下:
public class WrapMyRecyclerView extends RecyclerView { private Adapter mAdapter; private ArrayList<View> mHeaderViewInfos = new ArrayList<>();//保存headerView private ArrayList<View> mFooterViewInfos = new ArrayList<>();//保存footerView public WrapMyRecyclerView(Context context) { super(context); } public WrapMyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public WrapMyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * 添加headerView * @param v */ public void addHeaderView(View v) { mHeaderViewInfos.add(v); // Wrap the adapter if it wasn't already wrapped. if (mAdapter != null) { if (!(mAdapter instanceof RecyclerHeaderViewListAdapter)) { wrapHeaderListAdapterInternal(); } } } /** * 添加一個footerView * @param v */ public void addFooterView(View v) { mFooterViewInfos.add(v); // Wrap the adapter if it wasn't already wrapped. if (mAdapter != null) { if (!(mAdapter instanceof RecyclerHeaderViewListAdapter)) { wrapHeaderListAdapterInternal(); } } } /** * 設置一個Adapter * @param adapter */ @Override public void setAdapter(Adapter adapter) { if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) { mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } super.setAdapter(mAdapter); } private void wrapHeaderListAdapterInternal() { mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter); } /** * 新建一個RecyclerHeaderViewListAdapter對象 * 最終的adapter實現它 * @param headerViewInfos * @param footerViewInfos * @param adapter * @return */ protected RecyclerHeaderViewListAdapter wrapHeaderListAdapterInternal( ArrayList<View> headerViewInfos, ArrayList<View> footerViewInfos, Adapter adapter) { return new RecyclerHeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter); } }
這就是封裝的RecyclerView,里面主要有三個方法addHeaderView、 addFooterView和重寫的setAdapter。這里的唯一的思想就是偷梁換柱,當我們添加頭部、尾部或者設置adapter時,真正的adapter并不是我們傳入的adapter,而是重新new 了一個RecyclerHeaderViewListAdapter。這才是RecyclerView最終設置的adapter。
其實我們看到ListView也是通過這樣子的思想來添加頭部和尾部的。
這就是ListView的addHeaderView方法,它會偷偷的創建HeaderViewListAdapter這個adapter。最終添加的header和footer在HeaderViewListAdapter里面實現。
public class RecyclerHeaderViewListAdapter extends RecyclerView.Adapter { private final ArrayList<View> mHeaderViewInfos;//保存headerview數據 private final ArrayList<View> mFooterViewInfos;//保存footerView數據 private RecyclerView.Adapter mAdapter; //用戶自己構造的adapter private static final int RECYCLER_HEADER_VIEW = 0x001;//headerview類型 private static final int RECYCLER_FOOTER_VIEW = 0x002;//footerView類型 /** * 構造方法 * 初始化 * @param headerViewInfos * @param footerViewInfos * @param adapter */ public RecyclerHeaderViewListAdapter(ArrayList<View> headerViewInfos, ArrayList<View> footerViewInfos, RecyclerView.Adapter adapter) { mAdapter = adapter; if (headerViewInfos == null) { mHeaderViewInfos = new ArrayList<>(); } else { mHeaderViewInfos = headerViewInfos; } if (footerViewInfos == null) { mFooterViewInfos = new ArrayList<>(); } else { mFooterViewInfos = footerViewInfos; } } /** * 根據getItemViewType返回的條目類型 * 創建不同的itemview * 傳入的adapter,回調它的onCreateViewHolder即可 * @param parent * @param viewType * @return */ @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == RECYCLER_HEADER_VIEW){ return new HeaderViewLayout(mHeaderViewInfos.get(0)); }else if (viewType == RECYCLER_FOOTER_VIEW){ return new HeaderViewLayout(mFooterViewInfos.get(0)); } return mAdapter.onCreateViewHolder(parent,viewType); } /** * 綁定數據 * headerview和footerview不需要綁定數據,直接return即可 * 傳入的adapter需要回調它的onBindViewHolder即可 * @param holder * @param position */ @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { //header int numHeaders = getHeadersCount(); if (position < numHeaders) { return ; } //adapter body final int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { mAdapter.onBindViewHolder(holder, adjPosition); return ; } } //footer } /** * 返回條目的類型 * 傳入的adapter,回調它的getItemViewType即可 * @param position * @return */ @Override public int getItemViewType(int position) { // Header int numHeaders = getHeadersCount(); if (position < numHeaders) { return RECYCLER_HEADER_VIEW; } // Adapter final int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { return mAdapter.getItemViewType(position); } } // Footer (off-limits positions will throw an IndexOutOfBoundsException) return RECYCLER_FOOTER_VIEW; } /** * 總條目即:footerview的條目+headerview的條目+穿入的adapter條目 * @return */ @Override public int getItemCount() { if (mAdapter != null) { return getFootersCount() + getHeadersCount() + mAdapter.getItemCount(); } else { return getFootersCount() + getHeadersCount(); } } /** * 獲取headerview的條目 * @return */ public int getHeadersCount() { return mHeaderViewInfos.size(); } /** * 獲取footervie的條目 * @return */ public int getFootersCount() { return mFooterViewInfos.size(); } /** * 這是footerview和headerview的ViewHolder需要 * 這里只是提供一個構造器即可,實際上用處不大 */ private static class HeaderViewLayout extends RecyclerView.ViewHolder{ public HeaderViewLayout(View itemView) { super(itemView); } } }
這是實現添加header、footer和傳入adapter的RecyclerHeaderViewListAdapter。具體的邏輯都在文件的注釋里面有說明。邏輯是仿造ListView的HeaderViewListAdapter來實現的。
其實就是創建一個adapter,然后根據不同的條目類型來創建條目和綁定條目的數據即可。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.wrap.recycler.WrapRecyclerViewActivity"> <com.lwj.wrap.recycler.WrapMyRecyclerView android:id="@+id/wrap_recyclerview" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
這是布局文件
public class WrapRecyclerViewActivity extends AppCompatActivity { private WrapMyRecyclerView mRecyclerView; private MyAdapter mMyAdapter; private List<String> mList01 = new ArrayList<>(); private static final int WC = ViewGroup.LayoutParams.WRAP_CONTENT; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_wrap_recycler_view); getData(); mRecyclerView = (WrapMyRecyclerView) this.findViewById(R.id.wrap_recyclerview); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); //加入headerView ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(WC,WC); ImageView headerView = new ImageView(this); headerView.setImageResource(R.drawable.timg); headerView.setLayoutParams(params); mRecyclerView.addHeaderView(headerView); //設置adapter mMyAdapter = new MyAdapter(this,mList01); mRecyclerView.setAdapter(mMyAdapter); //加入footerView params = new ViewGroup.LayoutParams(WC,WC); ImageView footerView = new ImageView(this); footerView.setImageResource(R.drawable.hhfj); footerView.setLayoutParams(params); mRecyclerView.addFooterView(footerView); mMyAdapter.notifyDataSetChanged(); } public void getData() { for (int i = 0; i < 3; i++) { String data ="adapter...." + i; mList01.add(data); } } }
使用直接調用addHeaderView、addFooterView即可。
除了這種方式來實現addHeaderView和addFooterView,另外一種方式就是封裝Adapter來實現,原理還是保持不變:根據不同的條目類型來創建條目和綁定條目的數據。
public class MyCircleRecycViewAdapter extends RecyclerView.Adapter { public List<CircleInfo.CirclePageInfo> infos = null; private Context mContext; private ListViewImgLoader mLoader; private View VIEW_FOOTER;//尾部 private View VIEW_HEADER;//頭部 //Type private int TYPE_NORMAL = 1000; private int TYPE_HEADER = 1001; private int TYPE_FOOTER = 1002; private int tagType = TYPE_NORMAL; public MyCircleRecycViewAdapter(Context context,List<CircleInfo.CirclePageInfo> datas) { this.infos = datas; this.mContext = context; mLoader = new ListViewImgLoader(); mLoader.setMemoryCacheSize(1024 * 1024); mLoader.setVisibleItemCount(12); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_FOOTER) { tagType = TYPE_FOOTER; return new MyCircleItemHolder(VIEW_FOOTER); } else if (viewType == TYPE_HEADER) { tagType = TYPE_HEADER; return new MyCircleItemHolder(VIEW_HEADER); } else { tagType = TYPE_NORMAL; View view = LayoutInflater.from(mContext).inflate(R.layout.circle_gridview_items, parent,false); return new MyCircleItemHolder(view); } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (!isHeaderView(position) && !isFooterView(position)) { if (haveHeaderView()) position--; MyCircleItemHolder viewHolder = (MyCircleItemHolder)holder; CircleInfo.CirclePageInfo mInfo = infos.get(position); setData(viewHolder,mInfo); } } @Override public int getItemCount() { int count = (infos == null ? 0 : infos.size()); if (VIEW_FOOTER != null) { count++; } if (VIEW_HEADER != null) { count++; } return count; } @Override public int getItemViewType(int position) { if (isHeaderView(position)) { return TYPE_HEADER; } else if (isFooterView(position)) { return TYPE_FOOTER; } else { return TYPE_NORMAL; } } public void addHeaderView(View headerView) { if (haveHeaderView()) { throw new IllegalStateException("hearview has already exists!"); } else { //避免出現寬度自適應 ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(Utils.getRealPixel(30), Utils.getRealPixel(230)); headerView.setLayoutParams(params); VIEW_HEADER = headerView; notifyItemInserted(0); } } public void addFooterView(View footerView) { if (haveFooterView()) { throw new IllegalStateException("footerView has already exists!"); } else { ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); footerView.setLayoutParams(params); VIEW_FOOTER = footerView; // ifGridLayoutManager(); notifyItemInserted(getItemCount() - 1); } } private boolean haveHeaderView() { return VIEW_HEADER != null; } public boolean haveFooterView() { return VIEW_FOOTER != null; } private boolean isHeaderView(int position) { return haveHeaderView() && position == 0; } private boolean isFooterView(int position) { return haveFooterView() && position == getItemCount() - 1; } private void setData(final MyCircleItemHolder viewHolder, final CircleInfo.CirclePageInfo mInfo) { if(mInfo == null || mInfo == viewHolder.tagInfo) { return; }else{ viewHolder.tagInfo = mInfo; if(!StrUtils.isEnpty(mInfo.thread_unread)){ if(mInfo.thread_unread.equals("0")){ viewHolder.threaduUnreadTv.setVisibility(View.INVISIBLE); }else{ viewHolder.threaduUnreadTv.setVisibility(View.VISIBLE); viewHolder.threaduUnreadTv.setText(mInfo.thread_unread); } }else{ viewHolder.threaduUnreadTv.setVisibility(View.INVISIBLE); } if (!TextUtils.isEmpty(viewHolder.tagUrl)){ if(mInfo.circle_img_path != null && !(mInfo.circle_img_path.equals(viewHolder.tagUrl))){ setImage(viewHolder.mImageView,mInfo.circle_img_path); } }else{ setImage(viewHolder.mImageView,mInfo.circle_img_path); } if (!TextUtils.isEmpty(mInfo.circle_img_path)){ viewHolder.tagUrl = mInfo.circle_img_path; } if(mInfo.circleName != null){ if(mInfo.circleName.length() > 5){ String s = mInfo.circleName.substring(0,5) + "..."; viewHolder.textView.setText(s); }else{ viewHolder.textView.setText(mInfo.circleName); } } } } private void setImage(final ColorFilterImageView mImageView, final String imgUrl){ mImageView.setBackgroundColor(0xffadadad); mImageView.setImageBitmap(null); if(!TextUtils.isEmpty(imgUrl)) { mLoader.loadImage(mImageView.hashCode(), imgUrl, 300, new DnImg.OnDnImgListener() { @Override public void onProgress(String url, int downloadedSize, int totalSize) { // TODO Auto-generated method stub } @Override public void onFinish(String url, String file, Bitmap bmp) { if(url.equals(imgUrl)) { mImageView.setImageBitmap(bmp); } } }); }else{ mImageView.setBackgroundColor(0xffadadad); mImageView.setImageBitmap(null); } } class MyCircleItemHolder extends RecyclerView.ViewHolder{ private ColorFilterImageView mImageView; private TextView textView; private CircleInfo.CirclePageInfo tagInfo; private String tagUrl; private TextView threaduUnreadTv; public MyCircleItemHolder(final View itemView) { super(itemView); if(tagType == TYPE_NORMAL){ mImageView = (ColorFilterImageView)itemView.findViewById(R.id.quan_icon); mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); textView = (TextView)itemView.findViewById(R.id.quan_name); threaduUnreadTv = (TextView)itemView.findViewById(R.id.quan_num); mImageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mListener != null){ mListener.oncliItem(itemView,tagInfo,threaduUnreadTv); } } }); } } } public OnclickMyCircleItemListener mListener; public void setOnclickMyCircleItemListener(OnclickMyCircleItemListener l){ this.mListener = l; } public interface OnclickMyCircleItemListener{ void oncliItem(View view,CircleInfo.CirclePageInfo info,View threadNumTv); } public void pauseLoader(){ if(mLoader != null) { mLoader.pause(); } } public void resumeLoader(){ if(mLoader != null) { mLoader.resume(); } } public void closeLoader(){ if(mLoader != null) { mLoader.close(); } } }
總結
以上就是這篇文章的全部內容了,希望本文的內容對各位Android開發者們的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。