VLayout的使用

作者: 小和尚恋红尘 | 来源:发表于2018-02-27 13:24 被阅读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判断;这样的话新增功能越多,判定就加的越多,对于维护不利;所以这种写法虽然简单,但是不适合功能模块比较多的页面。

    相关文章

      网友评论

      本文标题:VLayout的使用

      本文链接:https://www.haomeiwen.com/subject/ygspxftx.html