学习收藏

VLayout的使用

2018-02-27  本文已影响34人  小和尚恋红尘

先来看看下面这个页面的实现:

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判断;这样的话新增功能越多,判定就加的越多,对于维护不利;所以这种写法虽然简单,但是不适合功能模块比较多的页面。

上一篇 下一篇

猜你喜欢

热点阅读