FormLayoutManager--多类型表格

FormLayoutManager首页,里面有github地址

目录

前言

代码

MonsterHAdapterByType

FormLayoutManager

注意


前言

之前能实现的表格都必须每个格子的宽高一样,现在所说的多类型就是,像平常的adapter一样,通过getItemViewType获取不同的类型,然后使用不同的布局。下面的讲解,你可知道,我只允许你根据行或根据列来获取不同类型(getRowItemViewType和getColumnItemViewType),这里不允许同时根据行和列来获取类型。接下来大家可以结合demo的HForm2Activity来理解。

代码

HForm2Activity跟其他demo里的界面代码没什么差别,主要还是要看Adapter和FormLayoutManager的代码。

MonsterHAdapterByType

    @Override
    protected int getColumnItemViewType(int column) {
        if (column == 1) {
            return TYPE_ATTRIBUTE;
        }
        if (column == 6 || column == 7) {
            return TYPE_MONSTER_TYPE;
        }
        return super.getColumnItemViewType(column);
    }

    @Override
    protected View createView(ViewGroup viewGroup, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.adapter_monster_form_item, viewGroup, false);

        if (viewType == TYPE_ATTRIBUTE) {
            view = LayoutInflater.from(mContext).inflate(R.layout.adapter_monster_form_item_attribute, viewGroup, false);
        }
        if (viewType == TYPE_MONSTER_TYPE) {
            view = LayoutInflater.from(mContext).inflate(R.layout.adapter_monster_form_item_type, viewGroup, false);
        }

        return view;
    }

可以看到这个adapter重写了一个getColumnItemViewType,根据不同列来返回类型,一共有两种类型和默认类型。createView也是对应有三个布局。

                                          

看看例子的界面,可以看到第2列和最后两列跟其他格子的宽有点不一样。

我们看一下基类BaseFormAdapter干了什么。

    @Override
    public int getItemViewType(int position) {
        int rowIndex = position / getColumnCount();
        int columnIndex = position % getColumnCount();
        int rowType = getRowItemViewType(rowIndex);
        int columnType = getColumnItemViewType(columnIndex);
        if (rowType != TYPE_DEFAULT){
            return rowType;
        }
        if (columnType != TYPE_DEFAULT){
            return columnType;
        }

        return TYPE_DEFAULT;
    }

    /**
     * 根据不同行获取itemViewType(注:与getColumnItemViewType只能重写其中一个)
     * @param row
     * @return
     */
    protected int getRowItemViewType(int row){
        return TYPE_DEFAULT;
    }

    /**
     *  根据不同列获取itemViewType (注:与getRowItemViewType只能重写其中一个)
     * @param column
     * @return
     */
    protected int getColumnItemViewType(int column){
        return TYPE_DEFAULT;
    }

其实只是重写一般adapter的getItemViewType,而getRowItemViewType和getColumnItemViewType默认返回一个默认类型,自己可以重写。而getItemViewType主要做的就是通过position获取该item对应的行row和列column。然后根据row获取行的类型,根据column获取列的类型,然后返回。

注意:

getRowItemViewType和getColumnItemViewType只能重写其中一个,我的库不允许你的表格,列的宽可以不同,同时行的高可以不同。你的表格要么就是根据列获取不同布局,或根据行获取不同布局。为什么?看上面那个demo例子,这个表格根据列返回三种类型,用了三个布局。如果现在这个表格有一行的高与其他行不一样,你不是要写多一个布局,而是要写多三个布局,因为与这行交叉的那个多类型的列,对应的itemview它的宽高跟其他itemview也不一样。所以你看多复杂,你要实现这么复杂的表格,你倒不如打开一张Excel表算了。

FormLayoutManager

接下来看看要实现多类型,FormLayoutManager要做出什么修改。当时FormLayoutManager -- 解说(1)里面有说过这样一段代码,在handleLayoutChildren里面的。

 for (int i = 0; i < getItemCount(); i++) {
            // item所在的行和列的index
            int row = i / mColumnCount;
            int column = i % mColumnCount;

            View itemView = recycler.getViewForPosition(i);
            Integer itemViewType = getItemViewType(itemView);
            int itemWidth;
            int itemHeight;
            if (mItemViewSizeMap.containsKey(itemViewType)){
                itemWidth = mItemViewSizeMap.get(itemViewType).width;
                itemHeight = mItemViewSizeMap.get(itemViewType).height;
            }else{
                measureChildWithMargins(itemView, 0, 0);
                itemWidth = getDecoratedMeasuredWidth(itemView);
                itemHeight = getDecoratedMeasuredHeight(itemView);
                mItemViewSizeMap.put(itemViewType, new ItemViewSize(itemWidth, itemHeight));
            }

            Rect rect = getViewRect(row, column, itemWidth, itemHeight);
            mItemRects.add(rect);
            mHasAttachedItems.add(false);
        }

我们的mItemRects列表就是用来保存表格所有格子的位置大小的,而解说(1)已经有说过怎么计算每个rect的left,top,right,bottom了,这里就不再说,我们主要看获取item类型的地方。

LayoutManager自带getItemViewType的方法,但要传入的是对应的view。这也没难度,拿到itemViewType的我们要干什么呢?

我们用一个mItemViewSizeMap来保存不同类型的view的宽高,类型作为key。如果map里面有该key,我们就可以从map里面拿出对应的宽高。如果没这个key,我们就用measureChildWithMargins测量这个itemView的宽高并保存。

只要拿到这个view准确的宽和高,通过getViewRect方法就可以获取对应的Rect。而这个getViewRect方法干了什么,解说(1)也有说,可以回看一下。

注意

1、只能根据行获取多类型或列获取多类型,不能同时重写两个获取类型的方法。

2、如果你的表格根据获取多类型,那你提供给表格的itemview的布局必须高都一样;如果你的表格根据获取多类型,那你提供给表格的itemview的表格必须宽一样。要不你的表格会不齐,错位的。

要符合上面这两点,才能正确使用多类型。后期我会再修改一下这个库,如果不符合上面的原则,会让你的程序抛异常。

发布了21 篇原创文章 · 获赞 14 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/DNWalter/article/details/104067726
今日推荐