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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章