Android 自訂View實現多行RadioGroup (MultiLineRadioGroup)

來源:互聯網
上載者:User

標籤:

一、項目概況

  我們都知道RadioGroup可以實現選擇框,但它有一個局限性,由於它是繼承自LinearLayout的,所以只能有一個方向,橫向或者縱向;但有時候僅一行的RadioGroup並不能滿足實際的需求,比如在一行的寬度下顯示不完所有的選項,設計上又不允許左右滑動,這時候RadioGroup就不能滿足這樣的功能設計了;基於此,我寫了這個MultiLineRadioGroup並且開源出來;

1、程式介面

 

 

2、功能介面

在Api開發上,能夠用到的功能及我能想到的,基本都已經添加完畢;具體如下:

  • child選項添加,刪除
  • child選項選中,取消選中
  • child對齊(左|中|右)
  • child行間距,左右間距
  • 設定選擇模式(單選|多選)
  • 擷取已選選項
  • child選擇狀態的監聽回調查

3、Demo連結地址

  https://github.com/a284628487/MultiLineRadioGroup

 

二、項目分析

1、基於上面的功能設計,為了設計方便,添加了一些自訂屬性;

    <declare-styleable name="MultiLineRadioGroup">        <attr name="child_margin_horizontal" format="dimension" />        <attr name="child_margin_vertical" format="dimension" />        <attr name="child_layout" format="integer" />        <attr name="child_count" format="integer" />        <attr name="child_values" format="integer" />        <attr name="single_choice" format="boolean" />        <attr name="gravity" format="integer" />    </declare-styleable>

上面的幾個自訂屬性分別表示

  • child水平間距
  • child上下間距
  • child對應的layout布局檔案(後面會講到,此屬性必須配置)
  • 初始元素個數
  • 初始元素值列表
  • 選擇模式(單選|多選)
  • child對齊

2、在layout中使用MultiLineRadioGroup

  (1)、定義一個包含MultiLineRadioGroup的xml檔案

    <org.ccflying.MultiLineRadioGroup        android:id="@+id/content"        android:layout_width="match_parent"        android:layout_height="wrap_content"        app:child_layout="@layout/child"        app:child_margin_horizontal="6.0dip"        app:child_margin_vertical="2.0dip"        app:child_values="@array/childvalues"        app:single_choice="true" >    </org.ccflying.MultiLineRadioGroup>

  (2)、定義一個根節點為CheckBox的layout檔案,並把該檔案id設定到MultiLineRadioGroup的child_layout屬性中(註:該屬性必須設定)

<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:background="@drawable/bg"    android:button="@null"    android:padding="8.0dip"    android:textColor="@color/text_color" ></CheckBox>

在MultiLineRadiaGroup中,它的子child元素為CheckBox,所以,必須指定一個要布局為CheckBox的child_layout,這個CheckBox可以根據你的需求設定它的不同狀態下的樣式;

 

3、MultiLineRadioGroup 核心方法分析

(1)、onMeasure

    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        childCount = getChildCount();        int flagX = 0, flagY = 0, sheight = 0;        if (childCount > 0) {            for (int i = 0; i < childCount; i++) {                View v = getChildAt(i);                measureChild(v, widthMeasureSpec, heightMeasureSpec);                int w = v.getMeasuredWidth() + childMarginHorizontal * 2                        + flagX + getPaddingLeft() + getPaddingRight();                if (w > getMeasuredWidth()) {                    flagY++;                    flagX = 0;                }                sheight = v.getMeasuredHeight();                flagX += v.getMeasuredWidth() + childMarginHorizontal * 2;            }            rowNumber = flagY;        }        int height = (flagY + 1) * (sheight + childMarginVertical)                + childMarginVertical + getPaddingBottom() + getPaddingTop();        setMeasuredDimension(getMeasuredWidth(), height);    }

遍曆所有的child,並且調用measureChild來對child進行寬高的測量,再通過對寬度的累加與getWidth的值進行比較來判斷是否需要換行,並且對需要用到的行數進行記錄;

(2)、onLayout

    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        if (!changed && !forceLayout) {            Log.d("tag", "onLayout:unChanged");            return;        }        childCount = getChildCount();        int[] sX = new int[rowNumber + 1];        if (childCount > 0) {            if (gravity != LEFT) {                for (int i = 0; i < childCount; i++) {                    View v = getChildAt(i);                    int w = v.getMeasuredWidth() + childMarginHorizontal * 2                            + mX + getPaddingLeft() + getPaddingRight();                    if (w > getWidth()) {                        if (gravity == CENTER) {                            sX[mY] = (getWidth() - mX) / 2;                        } else { // right                            sX[mY] = (getWidth() - mX);                        }                        mY++;                        mX = 0;                    }                    mX += v.getMeasuredWidth() + childMarginHorizontal * 2;                    if (i == childCount - 1) {                        if (gravity == CENTER) {                            sX[mY] = (getWidth() - mX) / 2;                        } else { // right                            sX[mY] = (getWidth() - mX);                        }                    }                }                mX = mY = 0;            }            for (int i = 0; i < childCount; i++) {                View v = getChildAt(i);                int w = v.getMeasuredWidth() + childMarginHorizontal * 2 + mX                        + getPaddingLeft() + getPaddingRight();                if (w > getWidth()) {                    mY++;                    mX = 0;                }                int startX = mX + childMarginHorizontal + getPaddingLeft()                        + sX[mY];                int startY = mY * v.getMeasuredHeight() + (mY + 1)                        * childMarginVertical;                v.layout(startX, startY, startX + v.getMeasuredWidth(), startY                        + v.getMeasuredHeight());                mX += v.getMeasuredWidth() + childMarginHorizontal * 2;            }        }        mX = mY = 0;        forceLayout = false;    }

和onMeasure一樣,onLayout方法也需要對child進行遍曆,不過,在這裡的遍曆就不是進行測量了,而是對child進行擺放,擺放的時候就需要用到onMeasure方法裡面所測量出的子項目的寬高等屬性;

遍曆可能會遍曆兩次,如果child對齊是非Left的情況下,第一次遍曆計算出每行的空隙,然後根據對齊算出每行的第一個child的位移left的距離,第二次遍曆的時候,再根據之前算出的位移距離對child進行layout; 

(3)、其它方法

  • append(String str) 附加一個child;
  • insert(int position, String str) 往指定位置插入child;
  • getCheckedValues()|getCheckedItems() 擷取選中項;
  • remove(int position) 刪除指定位置的child;
  • setItemChecked(int position) 選中指定位置的child;
  • setGravigy(int gravity) 設定child對齊;

這些方法都是根據常用或者可能用到的方法來進行實現的,比較簡單,就不再貼出代碼,上面的Demo連結中都有;

 

 

Over!

Android 自訂View實現多行RadioGroup (MultiLineRadioGroup)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.