vlayout 實戰之adapter封裝

本文主要講的是vlayout使用過程中,對適配器DelegateAdapter的封裝。實現了的效果,相當于傳統的Viewpager + 自由布局(此處還可以其他實現方式如GridView等) + ListView

先看看阿里巴巴的設計思路:
通過定制化的LayoutManager,接管整個RecyclerView的布局邏輯;LayoutManager管理了一系列LayoutHelper,LayoutHelper負責具體布局邏輯實現的地方;每一個LayoutHelper負責頁面某一個范圍內的組件布局;不同的LayoutHelper可以做不同的布局邏輯,因此可以在一個RecyclerView頁面里提供異構的布局結構,這就能比系統自帶的LinearLayoutManager、GridLayoutManager等提供更加豐富的能力。同時支持擴展LayoutHelper來提供更多的布局能力。

解析上面一段話就是:**RecyclerView + VirtualLayoutManager + DelegateAdapter **來實現各種布局,下面上一個本人的demo效果圖如下:



你沒有看錯,上面的視圖,就是有一個跟元素RecyclerView得來的。

話不多說,下面來分析,首先導入依賴(Module:app):

  compile ('com.alibaba.android:vlayout:1.0.9@aar') {
        transitive = true
    }

跟布局不用解釋,一個簡單的RecyclerView:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/main_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#fff"
        android:clipToPadding="true"
        android:paddingLeft="0dp"
        android:paddingRight="0dp"
        android:requiresFadingEdge="none"
        android:scrollbars="vertical"/>

</FrameLayout>

下面看MainActivity.java

import android.graphics.Rect;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

import com.alibaba.android.vlayout.DelegateAdapter;
import com.alibaba.android.vlayout.VirtualLayoutManager;
import com.alibaba.android.vlayout.layout.GridLayoutHelper;
import com.alibaba.android.vlayout.layout.LinearLayoutHelper;
import com.dingfang.org.testvlayout.adapter.BannerAdapter;
import com.dingfang.org.testvlayout.adapter.ClassficationAdapter;
import com.dingfang.org.testvlayout.adapter.ListAdapter;
import com.dingfang.org.testvlayout.util.RequestData;

import java.util.LinkedList;
import java.util.List;


public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView; //跟布局
    private VirtualLayoutManager layoutManager; //管理工具
    private DelegateAdapter delegateAdapter;    //適配器代理
    private List<DelegateAdapter.Adapter> adapters; //具體布局的適配器集合


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initWedgitAdapter();
        doCombine();
    }


    /**
     * 初始化視圖
     */
    private void initView() {
        recyclerView = (RecyclerView) findViewById(R.id.main_view);

        /**
         * 簽訂管理協議
         */
        layoutManager = new VirtualLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);

        /**
         * 設置適配器
         */
        delegateAdapter = new DelegateAdapter(layoutManager, true);//true or false 表示不同類型的adpter,item是否會復用
        recyclerView.setAdapter(delegateAdapter);

        /**
         * 具體布局的適配器 集合
         */
        adapters = new LinkedList<>();
    }

    /**
     * 初始化具體的布局
     */
    private void initWedgitAdapter() {
        //banner,可以滑動的廣告欄,就是圖中最上面部分
        adapters.add(new BannerAdapter(this, new LinearLayoutHelper(), new VirtualLayoutManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 300), RequestData.getImageViewsForBanner(this)));

        //圖中中間布局部分
        GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(4);//列,
        gridLayoutHelper.setVGap(4); // 垂直的間距
//        gridLayoutHelper.setWeights(new float[]{20.0f,30.0f,30.0f,20.0f}); //設置比例
        adapters.add(new ClassficationAdapter(this, gridLayoutHelper, RequestData.getLabels()));

        //圖中下面列表
        LinearLayoutHelper layoutHelper1 = new LinearLayoutHelper();
//        layoutHelper1.setAspectRatio(1.0f);// width / height,即寬高比
        layoutHelper1.setDividerHeight(10);
        adapters.add(new ListAdapter(this, layoutHelper1, RequestData.getListItems()));

    }

    /**
     * 最后的一步
     */
    private void doCombine() {
        delegateAdapter.setAdapters(adapters);
    }
}

上面代碼部分除了RequestData.getImageViewsForBanner(this)、RequestData.getLabels()、RequestData.getListItems()是我構造的假數據,為了不想臟了組件Activity。其余的,代碼中已經注釋很清楚了,不明白的可以留言哦~~~

其實上面代碼不是今天要講到的只要部分,下面才是重點,上面MainActivity.java中,在這段代碼中

  private void initWedgitAdapter() {
        //banner,可以滑動的廣告欄,就是圖中最上面部分
        adapters.add(new BannerAdapter(this, new LinearLayoutHelper(), new VirtualLayoutManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 300), RequestData.getImageViewsForBanner(this)));

        //圖中中間布局部分
        GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(4);//列,
        gridLayoutHelper.setVGap(4); // 垂直的間距
//        gridLayoutHelper.setWeights(new float[]{20.0f,30.0f,30.0f,20.0f}); //設置比例
        adapters.add(new ClassficationAdapter(this, gridLayoutHelper, RequestData.getLabels()));

        //圖中下面列表
        LinearLayoutHelper layoutHelper1 = new LinearLayoutHelper();
//        layoutHelper1.setAspectRatio(1.0f);// width / height,即寬高比
        layoutHelper1.setDividerHeight(10);
        adapters.add(new ListAdapter(this, layoutHelper1, RequestData.getListItems()));

    }

明顯有幾個Adapter,如BannerAdapter、ClassficationAdapter和ListAdapter,由于篇幅原因,下面先看其中一個ClassficationAdapter吧。

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.alibaba.android.vlayout.LayoutHelper;
import com.alibaba.android.vlayout.VirtualLayoutManager;
import com.dingfang.org.testvlayout.R;
import com.dingfang.org.testvlayout.adapter.base.BaseDelegateAdapter;
import com.dingfang.org.testvlayout.adapter.base.BaseViewHolder;
import com.dingfang.org.testvlayout.entity.LabelEntity;

import java.util.List;

/**
 * 宮格數據的適配器
 */

public class ClassficationAdapter  extends BaseDelegateAdapter<ClassficationAdapter.ClassficationViewHolder> {

    List<LabelEntity> labelEntities;

    public ClassficationAdapter() {
    }

    public ClassficationAdapter(Context mContext, LayoutHelper mLayoutHelper, List<LabelEntity> labelEntities) {
        this(mContext, mLayoutHelper, null, labelEntities);
    }

    public ClassficationAdapter(Context mContext, LayoutHelper mLayoutHelper, VirtualLayoutManager.LayoutParams mLayoutParams, List<LabelEntity> labelEntities) {
        super(mContext, mLayoutHelper, mLayoutParams);
        this.labelEntities = labelEntities;
    }

    @Override
    public ClassficationViewHolder doOnCreateViewHolder(ViewGroup parent, int viewType) {
        return new ClassficationViewHolder(LayoutInflater.from(this.getContext()).inflate(R.layout.label_item,parent,false));
    }

    @Override
    public void doOnBindViewHolder(ClassficationViewHolder holder, int position) {
        if (holder instanceof ClassficationViewHolder) {
            LabelEntity item = labelEntities.get(position);
            holder.imageView.setImageResource(item.getLabelImage());
            holder.textView.setText(item.getLabelText());
        }
    }

    @Override
    public int doGetItemCount() {
        return labelEntities == null ? 0 : labelEntities.size();
    }

    static class ClassficationViewHolder extends BaseViewHolder {
        public ImageView imageView;
        public TextView textView;

        public ClassficationViewHolder(View itemView) {
            super(itemView);
            imageView = (ImageView) itemView.findViewById(R.id.iv_label);
            textView = (TextView) itemView.findViewById(R.id.tv_label);
        }
    }
}

此適配器,是中間那個8個宮格數據的適配器,咦,它怎么繼承了BaseDelegateAdapter,并且ClassficationAdapter.ClassficationViewHolder也繼承了BaseViewHolder ,下面就來看看這兩個抽象類吧。

BaseDelegateAdapter.java ,本篇文章最值得看的部分

import android.content.Context;
import android.view.ViewGroup;

import com.alibaba.android.vlayout.DelegateAdapter;
import com.alibaba.android.vlayout.LayoutHelper;
import com.alibaba.android.vlayout.VirtualLayoutManager;

/**
 * 適配器抽象類
 */

public abstract class BaseDelegateAdapter <T extends BaseViewHolder> extends DelegateAdapter.Adapter<T>  {

    /**
     * 上下文環境
     * 提供get方法來獲取
     */
    private Context mContext;

    /**
     * 必要的布局管理屬性
     * 被框架管理,所以寫在抽象類里面
     */
    private LayoutHelper mLayoutHelper;

    /**
     * itemView布局中 跟布局的布局參數
     * 因為每一個實體類都要做此操作,所以也放在抽象類里面
     */
    private VirtualLayoutManager.LayoutParams mLayoutParams;

    public BaseDelegateAdapter() {

    }

    public BaseDelegateAdapter(Context mContext, LayoutHelper mLayoutHelper) {
        this(mContext,mLayoutHelper,null);
    }

    public BaseDelegateAdapter(Context mContext, LayoutHelper mLayoutHelper, VirtualLayoutManager.LayoutParams mLayoutParams) {
        this.mContext = mContext;
        this.mLayoutHelper = mLayoutHelper;
        this.mLayoutParams = mLayoutParams;
    }

    public Context getContext() {
        return mContext;
    }

    @Override
    public LayoutHelper onCreateLayoutHelper() {
        return this.mLayoutHelper;
    }

    @Override
    public T onCreateViewHolder(ViewGroup parent, int viewType) {
        return doOnCreateViewHolder(parent,viewType);
    }

    @Override
    public void onBindViewHolder(T holder, int position) {
        if (this.mLayoutParams != null) {
            holder.getView().setLayoutParams(this.mLayoutParams);//設置跟布局相關屬性
        }
        doOnBindViewHolder(holder, position);
    }

    @Override
    public int getItemCount() {
        return doGetItemCount();
    }

    //子類需要實現
    public abstract T doOnCreateViewHolder(ViewGroup parent, int viewType);
    public abstract void doOnBindViewHolder(T holder, int position);
    public abstract int doGetItemCount();
}

代碼淺顯易懂,不必多bb了,這里講阿里巴巴提供的DelegateAdapter,進行了封裝,這是本文的重點,可以細細評味下,不明白的可以評論哦~~~

BaseViewHolder.java ,這個就簡單了

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

/**
 * 通用的ViewHolider
 */

public abstract class BaseViewHolder extends RecyclerView.ViewHolder{
    private View itemView;

    public BaseViewHolder(View itemView) {
        super(itemView);
        this.itemView = itemView;
    }
    public View getView() {
        return this.itemView;
    }
}

好了代碼就貼這么多了,本文主要是提供一種思路和規范,通過BaseViewHolder,BaseDelegateAdapter這兩個抽象類來實現,使得繼承其的類不得不遵循相關的協議。

下面貼出demo地址
第一次寫,有沒有寫清楚的,歡迎大家一起討論~~~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,833評論 25 708
  • 簡介: 提供一個讓有限的窗口變成一個大數據集的靈活視圖。 術語表: Adapter:RecyclerView的子類...
    酷泡泡閱讀 5,202評論 0 16
  • 這篇文章分三個部分,簡單跟大家講一下 RecyclerView 的常用方法與奇葩用法;工作原理與ListView比...
    LucasAdam閱讀 4,413評論 0 27
  • 夢幻交響曲(組詩) 謝鶴仁 1)幽靈 沙漠立場不穩 胡楊沉默無語 一種生命要存活 首先是獨步,漂泊 尋找一片合適的...
    謝鶴仁閱讀 219評論 1 1
  • 以何承生命之輕 只依稀記得很多年以前,我重復著走著我家小鎮上的那條水泥街道,下過雨后的路上濕淋淋的,灰蒙蒙的天,...
    蘇家有妖孽閱讀 181評論 0 0