【從 0 開始開發一款直播 APP】3.2 高層封裝之 Adapter — RecyclerView 實現單佈局展示...

weixin_34321977發表於2017-04-06

本文為菜鳥窩作者蔣志碧的連載。“從 0 開始開發一款直播 APP ”系列來聊聊時下最火的直播 APP,如何完整的實現一個類"騰訊直播"的商業化專案
視訊地址:http://www.cniao5.com/course/10121


【從 0 開始開發一款直播 APP】3.1 高層封裝之 Adapter — ListView & GridView
【從 0 開始開發一款直播 APP】3.2 高層封裝之 Adapter — RecyclerView 實現單佈局展示
【從 0 開始開發一款直播 APP】3.3 高層封裝之 Adapter -- RecyclerView 實現多條目展示
【從 0 開始開發一款直播 APP】3.4 高層封裝之 Adapter -- RecyclerView 優雅的新增 Header、Footer


一、前言

之前已經講過 ListView、GridView 的 Adapter 封裝,這次將帶來 RecyclerView 的封裝。

RecyclerView 是一種新的檢視組,目標是為任何基於介面卡的檢視提供相似的渲染方式。該控制元件用於在有限的窗中展示大量資料集,它被作為 ListView 和 GridView 控制元件的繼承者。

主要有以下功能:

1、簡單資料繫結(單種 item)

2、多佈局繫結 (多種 item)

**3、設定監聽 **

4、優雅的新增 header、footer

老規矩,先封裝 ViewHolder,再封裝 Adapter。

二、ViewHolder 的封裝

2.1、RecyclerView 在使用之前需要新增依賴

dependencies {
    compile 'com.android.support:recyclerview-v7:25.2.0'
}

2.2、建立一個類繼承 RecyclerView.ViewHolder,實現其建構函式

public class RecyclerViewHolder extends RecyclerView.ViewHolder {
  public RecyclerViewHolder(View itemView) {
        super(itemView);
    }
}

2.3、其它的封裝和之前寫過對 Adapter 封裝類似,講了封裝的大致步驟,這裡不細講了,直接看 從 0 開始開發一款直播 APP | 3.1 高層封裝之 Adapter — ListView & GridView,一個 getView() 獲取控制元件,通過 SparseArray 儲存控制元件。

private SparseArray<View> mViews;

public RecyclerViewHolder(View itemView) {
    super(itemView);
    this.mViews = new SparseArray<>();
}

/**
 * 從ItemView獲取View
 * @param id  ItemView裡包含的ViewId
 * @param <V> 返回View
 * @return
 */
public <V extends View> V getView(int id) {
    View view = mViews.get(id);
    if (view == null) {
        view = itemView.findViewById(id);
        mViews.put(id, view);
    }
    return (V) view;
}

2.4、設定控制元件以及監聽(採用鏈式程式設計方法)

/**
 * 設定TextView的值
 * @param viewId
 * @param text
 * @return
 */
public RecyclerViewHolder setText(int viewId, String text) {
    TextView tv = getView(viewId);
    tv.setText(text);
    return this;
}

/**
 * 設定ImageView的值
 * @param viewId
 * @param resId
 * @return
 */
public RecyclerViewHolder setImageResource(int viewId, int resId) {
    ImageView view = getView(viewId);
    view.setImageResource(resId);
    return this;
}

/**
 * 設定ImageView的值
 * 第三方  ImageLoder Glide Picasso
 * 不能直接寫死第三方圖片載入
 * 使用自己的一套規範  ImageLoder
 * @param viewId
 * @return
 */
public RecyclerViewHolder setImagePath(int viewId,ImageLoder imageLoder) {
    ImageView view = getView(viewId);
    imageLoder.loadImage(view,imageLoder.getPath());
    return this;
}

//圖片載入 (對第三方庫載入圖片等封裝)
public abstract static class ImageLoder{
    private String path;
    public ImageLoder(String path){
        this.path = path;
    }
    //需要複寫該方法載入圖片
    public abstract void loadImage(ImageView imageView,String path);
    public String getPath() {
        return path;
    }
}

/**
 * 設定是否可見
 * @param viewId
 * @param visible
 * @return
 */
public RecyclerViewHolder setVisible(int viewId, boolean visible) {
    View view = getView(viewId);
    view.setVisibility(visible ? View.VISIBLE : View.GONE);
    return this;
}

/**
 * 設定tag
 * @param viewId
 * @param tag
 * @return
 */
public RecyclerViewHolder setTag(int viewId, Object tag) {
    View view = getView(viewId);
    view.setTag(tag);
    return this;
}

public RecyclerViewHolder setTag(int viewId, int key, Object tag) {
    View view = getView(viewId);
    view.setTag(key, tag);
    return this;
}

/**
 * 設定Checkable
 * @param viewId
 * @param checked
 * @return
 */
public RecyclerViewHolder setChecked(int viewId, boolean checked) {
    Checkable view = (Checkable) getView(viewId);
    view.setChecked(checked);
    return this;
}

//點選事件
public RecyclerViewHolder setOnClickListener(int viewId,View.OnClickListener listener) {
    View view = getView(viewId);
    view.setOnClickListener(listener);
    return this;
}

//觸控事件
public RecyclerViewHolder setOnTouchListener(int viewId,View.OnTouchListener listener) {
    View view = getView(viewId);
    view.setOnTouchListener(listener);
    return this;
}

//長按事件
public RecyclerViewHolder setOnLongClickListener(int viewId,View.OnLongClickListener listener) {
    View view = getView(viewId);
    view.setOnLongClickListener(listener);
    return this;
}

三、Adapter 的封裝

首先建立 Adapter 並繼承 RecyclerView.Adapter ,將 ViewHolder 作為範型傳入,將資料作為範型傳入,並實現其方法。方法和 ListView 封裝類似,傳入佈局,資料,上下文,通過 onCreateViewHolder() 例項化 ViewHolder,onBindViewHolder() 繫結 ViewHolder,用於資料,事件繫結,將該方法抽象出去,讓使用者實現,使用者通過該方法拿到 item 物件。

public abstract class RecyclerViewAdapter<T> extends RecyclerView.Adapter<RecyclerViewHolder> {
  
    protected int mLayoutId;//佈局id
    protected List<T> mDatas;//資料來源
    protected Context mContext;//上下文
    private LayoutInflater mInflater;

    public RecyclerViewAdapter(Context context, int layoutId, List<T> datas) {
        this.mContext = context;
        this.mLayoutId = layoutId;
        this.mDatas = datas;
        this.mInflater = LayoutInflater.from(mContext);
    }

    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = mInflater.inflate(mLayoutId,parent,false);
        return new RecyclerViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(RecyclerViewHolder holder, final int position) {
        bindData(holder,mDatas.get(position),position);
    }

    /**
     * 把必要引數傳進去,讓每個 Adapter 去設定具體值
     * @param holder RecyclerViewHolder 
     * @param t 資料
     * @param position 當前位置
     */
    protected abstract void bindData(RecyclerViewHolder holder, T t,int position);

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

四、Demo 演示單佈局顯示

4.1、由於用到網路圖片,我使用的Glide載入,先新增依賴

dependencies {
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.android.support:recyclerview-v7:25.2.0'
}

4.2、在 AndroidManifest.xml 中新增網路訪問許可權

    <uses-permission android:name="android.permission.INTERNET"/>

4.3、建立一個類繼承 RecyclerView.ViewHolder,實現其建構函式
RecyclerAdapterDemo.java

public class RecyclerAdapterDemo extends RecyclerViewAdapter<Item> {

    public RecyclerAdapterDemo(Context context, List<Item> datas) {
        super(context, R.layout.list_item, datas);
    }

    @Override
    protected void bindData(RecyclerViewHolder holder, final Item item, int position) {

        holder.setText(R.id.tv1,item.getTv1())
//                .setImageResource(R.id.img,item.getRes())
                .setOnClickListener(R.id.tv1, new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(mContext,item.getTv1(),Toast.LENGTH_SHORT).show();
                    }
                }).setOnLongClickListener(R.id.tv1, new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                Toast.makeText(mContext,"長按:"+item.getTv1(),Toast.LENGTH_SHORT).show();
                return true;//true 表示不響應點選事件 false 長按事件結束還會響應點選事件
            }
        });

        //載入網路圖片
        holder.setImagePath(R.id.img, new RecyclerViewHolder.ImageLoder("http://tomcat.apache.org/images/tomcat.png") {
            @Override
            public void loadImage(ImageView imageView, String path) {
                Glide.with(mContext).load(path).into(imageView);
            }
        });
    }
}

4.5、單佈局 Adapter 的使用

public class AdapterActivity extends BaseActivity {

    private RecyclerAdapterDemo mAdapterDemo;
    private ArrayList<Item> Datas;
    private RecyclerView mRecyclerView;

    @Override
    protected void setToolbar() {
    }

    @Override
    protected void setListener() {
    }

    //填充資料
    @Override
    protected void initData() {
        Datas = new ArrayList<>();
        for (int i = 1; i <= 30; i++) {
            Datas.add(new Item(R.drawable.tab_publish_normal,"我 get 新技能 " + i));
        }

        mAdapterDemo = new RecyclerAdapterDemo(this, Datas);
        mRecyclerView.setAdapter(mAdapterDemo);
    }

    @Override
    protected void initView() {
        mRecyclerView = obtainView(R.id.recyclerView);
        //LinearLayoutManager
        //新增分割線
        mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));  
        //新增布局管理器
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
      
      //分割線網上有很多示例,這裡不貼程式碼
        //GridLayoutManager
//        mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));
//        mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_adapter;
    }
}

4.6、activity_adapter.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.dali.admin.fragment.AdapterActivity">

   <android.support.v7.widget.RecyclerView
       android:id="@+id/recyclerView"
       android:layout_width="match_parent"
       android:layout_height="wrap_content">
   </android.support.v7.widget.RecyclerView>

</LinearLayout>

五、執行效果

**5.1、LinearLayoutManager **

5205232-60a0648d902f11ce.gif

5.2、GridLayoutManager

5205232-83aaaaa513562c9d.gif

總結

單條目封裝步驟

1、 ViewHolder 的封裝,繼承 RecyclerView.ViewHolder,實現其方法和建構函式
2、封裝 ViewHolder 的 getView() 方法,避免 findViewById 及型別轉換,提供設定控制元件和監聽的一系列方法
3、Adapter 的封裝,繼承 RecyclerView.Adapter 類,將封裝的 ViewHolder 作為範型傳入,將資料來源作為範型傳入。如:BaseAdapter<T> extends RecyclerView.Adapter<BaseViewHolder>。實現其構造方法和抽象方法。
4、設定資料來源,上下文物件,佈局 ID,抽象繫結 ViewHolder 具體實現,將 ViewHolder 和資料來源作為引數傳遞出去,讓使用者對資料進行相應處理。

單條目 Adapter 封裝及其使用講解完,下一章講解多條目 Adapter 封裝

更多內容,請關注菜鳥窩(微信公眾號ID: cniao5),程式猿的線上學習平臺。 轉載請註明出處,本文出自菜鳥窩,原文連結http://www.cniao5.com/forum/thread/107b6b5210fe11e790dc00163e0230fa

5205232-ef193ed0f98f726e.jpg
關注公眾號免費領取“N套客戶端實戰專案教程”

相關文章