本文主要講的是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地址
第一次寫,有沒有寫清楚的,歡迎大家一起討論~~~