本文主要讲的是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:
下面看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 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 {
List labelEntities;
public ClassficationAdapter() {
}
public ClassficationAdapter(Context mContext, LayoutHelper mLayoutHelper, List labelEntities) {
this(mContext, mLayoutHelper, null, labelEntities);
}
public ClassficationAdapter(Context mContext, LayoutHelper mLayoutHelper, VirtualLayoutManager.LayoutParams mLayoutParams, List 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 extends DelegateAdapter.Adapter {
/**
* 上下文环境
* 提供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地址
第一次写,有没有写清楚的,欢迎大家一起讨论~~~