先来看看下面这个页面的实现:
device-2018-02-27-102830.png按照我们平时的习惯,最后的布局文件如下:
<ScrollView>
<LinearLayout>
<ImageView> <顶部图片>
<LinearLayout><View/><TextView/><LinearLayout> <我的服务标题栏>
<GridView /> <我的服务功能块>
<LinearLayout><View/><TextView/><LinearLayout> <我的功能标题栏>
<GridView /> <我的功能功能块>
<LinearLayout>
<ScrollView/>
可以看出,布局很复杂。如果在想加一个“我的售后”模块呢,就需要找到相应的布局代码,在相应的位置加上布局代码,这样很麻烦,不利于扩展...
下面我们来看看阿里巴巴开源的vlayout
对于上面的页面我们来使用VLayout
来进行实现,我们先看看布局代码:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rv_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
整个页面的布局,就只有一个RecyclerView
控件,简单吧...
它的功能实现,有两种写法,首先我们来看看比较通用点的实现,它的思路大概就是:为每个模块建立一个Adapter
,然后将这些Adapter
放入一个总集合中,最后把这个集合设置给RecyclerView
。
上面的页面,我们可以分为三个模块:顶部图片,标题栏,功能块。这样对应的也就有三个Adapter
,依次如下:
//顶部图片BannerAdapter
public class BannerAdapter extends DelegateAdapter.Adapter<BannerAdapter.ViewHolder> {
private Context context;
private List<Integer> urls;
private LayoutHelper layoutHelper;
public BannerAdapter(Context context, List<Integer> urls, LayoutHelper layoutHelper){
this.context = context;
this.urls = urls;
this.layoutHelper = layoutHelper;
}
@Override
public LayoutHelper onCreateLayoutHelper() {
return layoutHelper;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item_banner, parent, false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Glide.with(context).load(urls.get(position)).into(holder.imageView);
}
@Override
public int getItemCount() {
return urls.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.iv_banner);
}
}
}
//标题栏DividerAdapter
public class DividerAdapter extends DelegateAdapter.Adapter<DividerAdapter.DividerViewHolder> {
private Context context;
private List<String> itemBeanList;
private LayoutHelper layoutHelper;
public DividerAdapter(Context context, List<String> itemBeanList, LayoutHelper layoutHelper){
this.context = context;
this.itemBeanList = itemBeanList;
this.layoutHelper = layoutHelper;
}
@Override
public LayoutHelper onCreateLayoutHelper() {
return layoutHelper;
}
@Override
public DividerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new DividerViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item_divider, parent, false));
}
@Override
public void onBindViewHolder(DividerViewHolder holder, int position) {
holder.tvName.setText(itemBeanList.get(position));
}
@Override
public int getItemCount() {
return itemBeanList.size();
}
public class DividerViewHolder extends RecyclerView.ViewHolder{
private TextView tvName;
public DividerViewHolder(View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tv_name);
}
}
}
//功能块ContentAdapter
public class ContentAdapter extends DelegateAdapter.Adapter<ContentAdapter.ContentViewHolder> {
private Context context;
private List<ItemBean> itemBeanList;
private LayoutHelper layoutHelper;
public ContentAdapter(Context context, List<ItemBean> itemBeanList, LayoutHelper layoutHelper){
this.context = context;
this.itemBeanList = itemBeanList;
this.layoutHelper = layoutHelper;
}
@Override
public LayoutHelper onCreateLayoutHelper() {
return layoutHelper;
}
@Override
public ContentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ContentViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item_content, parent, false));
}
@Override
public void onBindViewHolder(ContentViewHolder holder, int position) {
Glide.with(context).load(Integer.parseInt(itemBeanList.get(position).getImgUrl())).into(holder.icon);
holder.tvName.setText(itemBeanList.get(position).getName());
}
@Override
public int getItemCount() {
return itemBeanList.size();
}
public class ContentViewHolder extends RecyclerView.ViewHolder{
private ImageView icon;
private TextView tvName;
public ContentViewHolder(View itemView) {
super(itemView);
icon = itemView.findViewById(R.id.iv_icon);
tvName = itemView.findViewById(R.id.tv_name);
}
}
}
这样各个模块的适配器就写完了,下面就是使用了...
VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);//建立我们的委托LayoutManger
rvLayout.setLayoutManager(layoutManager);
/**
* 目前的LayoutHelper有以下几种:
*
* LinearLayoutHelper: 线性布局
* GridLayoutHelper: Grid布局, 支持横向的colspan
* FixLayoutHelper: 固定布局,始终在屏幕固定位置显示
* ScrollFixLayoutHelper: 固定布局,但之后当页面滑动到该图片区域才显示, 可以用来做返回顶部或其他书签等
* FloatLayoutHelper: 浮动布局,可以固定显示在屏幕上,但用户可以拖拽其位置
* ColumnLayoutHelper: 栏格布局,都布局在一排,可以配置不同列之间的宽度比值
* SingleLayoutHelper: 通栏布局,只会显示一个组件View
* OnePlusNLayoutHelper: 一拖N布局,可以配置1-5个子元素
* StickyLayoutHelper: stikcy布局, 可以配置吸顶或者吸底
* StaggeredGridLayoutHelper: 瀑布流布局,可配置间隔高度/宽度
*/
//顶部图片
SingleLayoutHelper bannerLayoutHelper = new SingleLayoutHelper();
bannerLayoutHelper.setItemCount(1);//设置子条目个数
List<Integer> imgList = new ArrayList<>();
imgList.add(R.drawable.banner);
adapters.add(new BannerAdapter(this, imgList, bannerLayoutHelper));
//第一个标题栏:我的服务
LinearLayoutHelper serverLayoutHelper = new LinearLayoutHelper();
serverLayoutHelper.setItemCount(1);
List<String> list = new ArrayList<>();
list.add("我的服务");
adapters.add(new DividerAdapter(this, list, serverLayoutHelper));
//我的服务,功能块
GridLayoutHelper serverGridLayoutHelper = new GridLayoutHelper(3);
serverGridLayoutHelper.setAutoExpand(false);//是否自动扩展
serverGridLayoutHelper.setWeights(new float[]{33, 33, 33});//设置权重
serverGridLayoutHelper.setItemCount(6);
adapters.add(new ContentAdapter(this, serverList, serverGridLayoutHelper));
//第二个标题栏:我的功能
LinearLayoutHelper functionLayoutHelper = new LinearLayoutHelper();
functionLayoutHelper.setItemCount(1);
layoutHelperList.add(functionLayoutHelper);
List<String> list1 = new ArrayList<>();
list1.add("我的功能");
adapters.add(new DividerAdapter(this, list1, functionLayoutHelper));
//我的功能,功能块
GridLayoutHelper functionGridLayoutHelper = new GridLayoutHelper(3);
functionGridLayoutHelper.setAutoExpand(false);
functionGridLayoutHelper.setWeights(new float[]{33, 33, 33});
functionGridLayoutHelper.setItemCount(6);
adapters.add(new ContentAdapter(this, functionList, functionGridLayoutHelper));
DelegateAdapter adapter1 = new DelegateAdapter(layoutManager, false);
adapter1.setAdapters(adapters);//添加不同的子Adapter.
rvLayout.setAdapter(adapter1);
这样就完成了,对上面页面的实现。
如果我想新加一个功能块,我们只需要针对这个功能块,新建一个Adapter
,在将其加入集合adapters
中就可以了,不需要在去更改原来的代码了....
我们在来看看另一种写法,它的大概思路就是:为每个模块设置一个LayoutHelper
,然后将其放入LayoutHelper集合中
,在将此集合设置给VirtualLayoutManager
,最后在Adapter
中进行具体的处理。具体代码如下:
VirtualLayoutManager layoutManager = new VirtualLayoutManager(this);
rvLayout.setLayoutManager(layoutManager);
getData();//获取数据
/**
* 目前的LayoutHelper有以下几种:
* LinearLayoutHelper: 线性布局
* GridLayoutHelper: Grid布局, 支持横向的colspan
* FixLayoutHelper: 固定布局,始终在屏幕固定位置显示
* ScrollFixLayoutHelper: 固定布局,但之后当页面滑动到该图片区域才显示, 可以用来做返回顶部或其他书签等
* FloatLayoutHelper: 浮动布局,可以固定显示在屏幕上,但用户可以拖拽其位置
* ColumnLayoutHelper: 栏格布局,都布局在一排,可以配置不同列之间的宽度比值
* SingleLayoutHelper: 通栏布局,只会显示一个组件View
* OnePlusNLayoutHelper: 一拖N布局,可以配置1-5个子元素
* StickyLayoutHelper: stikcy布局, 可以配置吸顶或者吸底
* StaggeredGridLayoutHelper: 瀑布流布局,可配置间隔高度/宽度
*/
List<LayoutHelper> layoutHelperList = new ArrayList<>();
//顶部图片
SingleLayoutHelper bannerLayoutHelper = new SingleLayoutHelper();
bannerLayoutHelper.setItemCount(1);
layoutHelperList.add(bannerLayoutHelper);
//我的服务标题栏
LinearLayoutHelper serverLayoutHelper = new LinearLayoutHelper();
serverLayoutHelper.setItemCount(1);
layoutHelperList.add(serverLayoutHelper);
//我的服务
GridLayoutHelper serverGridLayoutHelper = new GridLayoutHelper(3);
serverGridLayoutHelper.setAutoExpand(false);
serverGridLayoutHelper.setWeights(new float[]{33, 33, 33});
serverGridLayoutHelper.setItemCount(6);
layoutHelperList.add(serverGridLayoutHelper);
//我的功能标题栏
LinearLayoutHelper functionLayoutHelper = new LinearLayoutHelper();
functionLayoutHelper.setItemCount(1);
layoutHelperList.add(functionLayoutHelper);
//我的功能
GridLayoutHelper functionGridLayoutHelper = new GridLayoutHelper(3);
functionGridLayoutHelper.setAutoExpand(false);
functionGridLayoutHelper.setWeights(new float[]{33, 33, 33});
functionGridLayoutHelper.setItemCount(6);
layoutHelperList.add(functionGridLayoutHelper);
layoutManager.setLayoutHelpers(layoutHelperList);//设置LayoutHelper集合
VLayoutAdapter adapter = new VLayoutAdapter(layoutManager, this, serverList, functionList);
rvLayout.setAdapter(adapter);
//整体Adapter
public class VLayoutAdapter extends VirtualLayoutAdapter {
private int serverNum;
private int functionNum;
private Context context;
private List<ItemBean> serverList = new ArrayList<>();
private List<ItemBean> functionList = new ArrayList<>();
private final int FLAG_BANNER = 1;//banner
private final int FLAG_DIVIDER = 2;//标题栏
private final int FLAG_CONTENT = 3;//功能块
public VLayoutAdapter(@NonNull VirtualLayoutManager layoutManager, Context context, List<ItemBean> serverList, List<ItemBean> functionList) {
super(layoutManager);
this.serverList = serverList;
this.functionList = functionList;
this.context = context;
serverNum = serverList.size();
functionNum = functionList.size();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType){
case FLAG_BANNER:
return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_banner, parent, false));
case FLAG_DIVIDER:
return new DividerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_divider, parent, false));
case FLAG_CONTENT:
return new ContentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_content, parent, false));
default:
return null;
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof BannerViewHolder){
Glide.with(context).load(R.drawable.banner).into(((BannerViewHolder) holder).banner);
}else if (holder instanceof DividerViewHolder){
if (position == 1){
((DividerViewHolder) holder).tvName.setText("我的服务");
((DividerViewHolder) holder).tvName.setTextColor(Color.parseColor("#F9C025"));
}else{
((DividerViewHolder) holder).tvName.setText("我的功能");
((DividerViewHolder) holder).tvName.setTextColor(Color.parseColor("#35A7FF"));
}
}else if (holder instanceof ContentViewHolder){
if (position > 1 && position < 2+serverNum){
((ContentViewHolder) holder).tvName.setText(serverList.get(position-2).getName());
Glide.with(context).load(Integer.parseInt(serverList.get(position-2).getImgUrl())).into(((ContentViewHolder) holder).icon);
}else if (position > 2+serverNum){
((ContentViewHolder) holder).tvName.setText(functionList.get(position-(2+serverNum+1)).getName());
Glide.with(context).load(Integer.parseInt(functionList.get(position-(2+serverNum+1)).getImgUrl())).into(((ContentViewHolder) holder).icon);
}
}
}
@Override
public int getItemCount() {//返回总条目数
int totalCount = 0;
List<LayoutHelper> helpers = getLayoutHelpers();//获取全部的LayoutHelper
if (helpers == null ) {
return 0;
}
for (int i = 0; i < helpers.size(); i++) {
totalCount += helpers.get(i).getItemCount();//获取LayoutHelper中的子条目数
}
return totalCount;
}
@Override
public int getItemViewType(int position) {
if (position == 0){
return FLAG_BANNER;
}else if (position == 1 || position == (2+serverNum)){
return FLAG_DIVIDER;
}else {
return FLAG_CONTENT;
}
}
public class BannerViewHolder extends RecyclerView.ViewHolder{
private ImageView banner;
public BannerViewHolder(View itemView) {
super(itemView);
banner = itemView.findViewById(R.id.iv_banner);
}
}
public class DividerViewHolder extends RecyclerView.ViewHolder{
private TextView tvName;
public DividerViewHolder(View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tv_name);
}
}
public class ContentViewHolder extends RecyclerView.ViewHolder{
private ImageView icon;
private TextView tvName;
public ContentViewHolder(View itemView) {
super(itemView);
icon = itemView.findViewById(R.id.iv_icon);
tvName = itemView.findViewById(R.id.tv_name);
}
}
}
从上面的adapter代码中可以看出,如果我新加一个功能模块,那么就得新加一个标识类型,在onBindViewHolder
中就得多加一条if..else判断;这样的话新增功能越多,判定就加的越多,对于维护不利;所以这种写法虽然简单,但是不适合功能模块比较多的页面。
网友评论