Android Custom View implements multi-line Radiogroup (Multilineradiogroup)

Source: Internet
Author: User

I. Overview of the Project

We all know that Radiogroup can implement a selection box, but it has a limitation, because it is inherited from the linearlayout, so there can only be one direction, horizontal or vertical; but sometimes a single line of Radiogroup does not meet the actual needs, For example, in a row of the width of the display of all the options, the design is not allowed to slide left and right, at this time Radiogroup can not meet such a function design, based on this, I wrote this multilineradiogroup and open source;

1. Program Interface

2. Function interface

In the API development, the ability to use and I can think of, the basic has been added, specifically as follows:

    • The child option is added, removed
    • The child option is selected, unchecked
    • Child Alignment (left | middle | right)
    • Child line spacing, left and right spacing
    • Set selection mode (Single selection | multiple selection)
    • Get selected options
    • Child Select State Listener back to investigate

3. Demo Link Address

Https://github.com/a284628487/MultiLineRadioGroup

Second, the project analysis

1, based on the above function design, in order to design convenience, added some custom attributes;

    <declare-styleablename= "Multilineradiogroup">        <attrname= "Child_margin_horizontal"format= "Dimension" />        <attrname= "Child_margin_vertical"format= "Dimension" />        <attrname= "Child_layout"format= "integer" />        <attrname= "Child_count"format= "integer" />        <attrname= "Child_values"format= "integer" />        <attrname= "Single_choice"format= "Boolean" />        <attrname= "Gravity"format= "integer" />    </declare-styleable>

Several of the above custom properties represent

    • Child Horizontal Spacing
    • Child up/down spacing
    • The layout file corresponding to child (as described later, this property must be configured)
    • Number of initial elements
    • Initial element Value List
    • Select Mode (Single selection | multiple selection)
    • Child alignment

2. Use Multilineradiogroup in Layout

(1), define an XML file that contains Multilineradiogroup

    <Org.ccflying.MultiLineRadioGroupAndroid: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), define a layout file with a checkbox for the root node and set the file ID to the Child_layout attribute of the Multilineradiogroup ( Note: This property must be set )

<CheckBoxxmlns: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>

In Multilineradiagroup, its child children element is a checkbox, so you must specify a child_layout to be laid out as a checkbox, which can be styled according to your needs in different states;

3, Multilineradiogroup Core method analysis

(1), onmeasure

@Overrideprotected voidOnmeasure (intWidthmeasurespec,intHeightmeasurespec) {        Super. Onmeasure (Widthmeasurespec, Heightmeasurespec); ChildCount=Getchildcount (); intFLAGX = 0, flagy = 0, sheight = 0; if(ChildCount > 0) {             for(inti = 0; i < ChildCount; i++) {View v=Getchildat (i);                Measurechild (V, Widthmeasurespec, Heightmeasurespec); intW = v.getmeasuredwidth () + childmarginhorizontal * 2 + FLAGX + getpaddingleft () +getpaddingright (); if(W >getmeasuredwidth ()) {Flagy++; FLAGX= 0; } sheight=v.getmeasuredheight (); FLAGX+ = V.getmeasuredwidth () + childmarginhorizontal * 2; } rowNumber=Flagy; }        intHeight = (flagy + 1) * (Sheight +childmarginvertical)+ childmarginvertical + getpaddingbottom () +Getpaddingtop ();    Setmeasureddimension (Getmeasuredwidth (), height); }

Traverse all of the child, and call Measurechild to make a wide measurement of the child, and then by comparing the width of the summation with the value of the getwidth to determine if the need to wrap, and the number of rows to be used to record;

(2), onlayout

@Overrideprotected voidOnLayout (BooleanChangedintLintTintRintb) {if(!changed &&!)forcelayout) {LOG.D ("Tag", "Onlayout:unchanged"); return; } ChildCount=Getchildcount (); int[] SX =New int[RowNumber + 1]; if(ChildCount > 0) {            if(Gravity! =Left ) {                 for(inti = 0; i < ChildCount; i++) {View v=Getchildat (i); intW = v.getmeasuredwidth () + childmarginhorizontal * 2 + MX + getpaddingleft () +getpaddingright (); if(W >getwidth ()) {                        if(Gravity = =CENTER) {Sx[my]= (GetWidth ()-MX)/2; } Else{// RightSx[my] = (getwidth ()-MX); } MY++; MX= 0; } MX+ = V.getmeasuredwidth () + childmarginhorizontal * 2; if(i = = ChildCount-1) {                        if(Gravity = =CENTER) {Sx[my]= (GetWidth ()-MX)/2; } Else{// RightSx[my] = (getwidth ()-MX); }}} MX= MY = 0; }             for(inti = 0; i < ChildCount; i++) {View v=Getchildat (i); intW = v.getmeasuredwidth () + childmarginhorizontal * 2 +MX+ getpaddingleft () +getpaddingright (); if(W >getwidth ()) {MY++; MX= 0; }                intStartX = MX + childmarginhorizontal +Getpaddingleft ()+Sx[my]; intStarty = 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; }

As with Onmeasure, the OnLayout method also needs to traverse the child, however, the traversal here is not the measurement, but the children are placed, placed on the need to use the Onmeasure method inside the measured sub-elements of the width of the higher attributes;

The traversal may traverse two times, and if the child alignment is non-left, the first traversal calculates the gap for each row, then the offset left distance of the first child of each line is calculated according to the alignment, and the second traversal, The child is then layout according to the offset distance previously calculated;

(3), other methods

    • Append (String str) attaching a child;
    • Insert (int position, String str) inserts child at the specified position;
    • Getcheckedvalues () |getcheckeditems () gets the selected item;
    • Remove (int position) deletes the child at the specified position;
    • setitemchecked (int position) selects child at the specified position;
    • Setgravigy (int gravity) sets the child alignment;

These methods are based on common or possible use of methods to implement, relatively simple, no longer posted code, the above demo links are;

over!

Android Custom View implements multi-line Radiogroup (Multilineradiogroup)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.