Android 自訂RadioGroup布局

來源:互聯網
上載者:User

標籤:android   radiobutton   布局   layout   源碼   

前段時間項目中需要這種效果,自訂RadioGroup布局,但是前提是要找到RadioButton。我搜集各種資料,嘗試各種測試。終於有了自訂RadioGroup布局。自定RadioGroup布局,裡面可以包含各種布局,RadioButton也在這裡面的布局。通過遞迴尋找方法能找到RadioButton的id,還是一組的。接下來看代碼。

轉載請註明出處:單擊此處

歡迎下載測試demo:單擊此處

一、自訂CustomNestRadioGroup類。

package com.example.customgroupdemo;import android.annotation.TargetApi;import android.content.Context;import android.content.res.TypedArray;import android.os.Build;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import android.widget.CompoundButton;import android.widget.LinearLayout;//這個類是源碼RadioGroup複製出來,增加了遞迴尋找子控制項RadioButtonpublic class CustomNestRadioGroup extends LinearLayout {// holds the checked id; the selection is empty by defaultprivate int mCheckedId = -1;// tracks children radio buttons checked stateprivate CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;// when true, mOnCheckedChangeListener discards eventsprivate boolean mProtectFromCheckedChange = false;private OnCheckedChangeListener mOnCheckedChangeListener;private PassThroughHierarchyChangeListener mPassThroughListener;/** * {@inheritDoc} */public CustomNestRadioGroup(Context context) {super(context);init();}/** * {@inheritDoc} */public CustomNestRadioGroup(Context context, AttributeSet attrs) {super(context, attrs);init();}private void init() {mCheckedId = View.NO_ID;//setOrientation(VERTICAL);   //可以在這裡設定線性布局方向mChildOnCheckedChangeListener = new CheckedStateTracker();mPassThroughListener = new PassThroughHierarchyChangeListener();super.setOnHierarchyChangeListener(mPassThroughListener);}/** * {@inheritDoc} */@Overridepublic void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {// the user listener is delegated to our pass-through listenermPassThroughListener.mOnHierarchyChangeListener = listener;}/** * {@inheritDoc} */@Overrideprotected void onFinishInflate() {super.onFinishInflate();// checks the appropriate radio button as requested in the XML fileif (mCheckedId != View.NO_ID) {mProtectFromCheckedChange = true;setCheckedStateForView(mCheckedId, true);mProtectFromCheckedChange = false;setCheckedId(mCheckedId);}}/** 遞迴尋找具有選中屬性的子控制項 */private static CompoundButton findCheckedView(View child) {if (child instanceof CompoundButton)return (CompoundButton) child;if (child instanceof ViewGroup) {ViewGroup group = (ViewGroup) child;for (int i = 0, j = group.getChildCount(); i < j; i++) {CompoundButton check = findCheckedView(group.getChildAt(i));if (check != null)return check;}}return null;// 沒有找到}@Overridepublic void addView(View child, int index, ViewGroup.LayoutParams params) {final CompoundButton view = findCheckedView(child);if (view != null) {if (view.isChecked()) {mProtectFromCheckedChange = true;if (mCheckedId != -1) {setCheckedStateForView(mCheckedId, false);}mProtectFromCheckedChange = false;setCheckedId(view.getId());}}super.addView(child, index, params);}/** * <p> * Sets the selection to the radio button whose identifier is passed in * parameter. Using -1 as the selection identifier clears the selection; * such an operation is equivalent to invoking {@link #clearCheck()}. * </p> *  * @param id *            the unique id of the radio button to select in this group *  * @see #getCheckedRadioButtonId() * @see #clearCheck() */public void check(int id) {// don't even botherif (id != -1 && (id == mCheckedId)) {return;}if (mCheckedId != -1) {setCheckedStateForView(mCheckedId, false);}if (id != -1) {setCheckedStateForView(id, true);}setCheckedId(id);}private void setCheckedId(int id) {mCheckedId = id;if (mOnCheckedChangeListener != null) {mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);}}private void setCheckedStateForView(int viewId, boolean checked) {View checkedView = findViewById(viewId);if (checkedView != null && checkedView instanceof CompoundButton) {((CompoundButton) checkedView).setChecked(checked);}}/** * <p> * Returns the identifier of the selected radio button in this group. Upon * empty selection, the returned value is -1. * </p> *  * @return the unique id of the selected radio button in this group *  * @see #check(int) * @see #clearCheck() *  * @attr ref android.R.styleable#CustomNestRadioGroup_checkedButton */public int getCheckedRadioButtonId() {return mCheckedId;}/** * <p> * Clears the selection. When the selection is cleared, no radio button in * this group is selected and {@link #getCheckedRadioButtonId()} returns * null. * </p> *  * @see #check(int) * @see #getCheckedRadioButtonId() */public void clearCheck() {check(-1);}/** * <p> * Register a callback to be invoked when the checked radio button changes * in this group. * </p> *  * @param listener *            the callback to call on checked state change */public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {mOnCheckedChangeListener = listener;}/** * {@inheritDoc} */@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new CustomNestRadioGroup.LayoutParams(getContext(), attrs);}/** * {@inheritDoc} */@Overrideprotected boolean checkLayoutParams(ViewGroup.LayoutParams p) {return p instanceof CustomNestRadioGroup.LayoutParams;}@Overrideprotected LinearLayout.LayoutParams generateDefaultLayoutParams() {return new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);}/** * <p> * This set of layout parameters defaults the width and the height of the * children to {@link #WRAP_CONTENT} when they are not specified in the XML * file. Otherwise, this class ussed the value read from the XML file. * </p> *  * <p> * See {@link android.R.styleable#LinearLayout_Layout LinearLayout * Attributes} for a list of all child view attributes that this class * supports. * </p> *  */public static class LayoutParams extends LinearLayout.LayoutParams {/** * {@inheritDoc} */public LayoutParams(Context c, AttributeSet attrs) {super(c, attrs);}/** * {@inheritDoc} */public LayoutParams(int w, int h) {super(w, h);}/** * {@inheritDoc} */public LayoutParams(int w, int h, float initWeight) {super(w, h, initWeight);}/** * {@inheritDoc} */public LayoutParams(ViewGroup.LayoutParams p) {super(p);}/** * {@inheritDoc} */public LayoutParams(MarginLayoutParams source) {super(source);}/** * <p> * Fixes the child's width to * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} and the * child's height to * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} when not * specified in the XML file. * </p> *  * @param a *            the styled attributes set * @param widthAttr *            the width attribute to fetch * @param heightAttr *            the height attribute to fetch */@Overrideprotected void setBaseAttributes(TypedArray a, int widthAttr,int heightAttr) {if (a.hasValue(widthAttr)) {width = a.getLayoutDimension(widthAttr, "layout_width");} else {width = WRAP_CONTENT;}if (a.hasValue(heightAttr)) {height = a.getLayoutDimension(heightAttr, "layout_height");} else {height = WRAP_CONTENT;}}}/** * <p> * Interface definition for a callback to be invoked when the checked radio * button changed in this group. * </p> */public interface OnCheckedChangeListener {/** * <p> * Called when the checked radio button has changed. When the selection * is cleared, checkedId is -1. * </p> *  * @param group *            the group in which the checked radio button has changed * @param checkedId *            the unique identifier of the newly checked radio button */public void onCheckedChanged(CustomNestRadioGroup group, int checkedId);}private class CheckedStateTracker implementsCompoundButton.OnCheckedChangeListener {public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {// prevents from infinite recursionif (mProtectFromCheckedChange) {return;}mProtectFromCheckedChange = true;if (mCheckedId != -1) {setCheckedStateForView(mCheckedId, false);}mProtectFromCheckedChange = false;int id = buttonView.getId();setCheckedId(id);}}/** * <p> * A pass-through listener acts upon the events and dispatches them to * another listener. This allows the table layout to set its own internal * hierarchy change listener without preventing the user to setup his. * </p> */private class PassThroughHierarchyChangeListener implementsViewGroup.OnHierarchyChangeListener {private ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;/** * {@inheritDoc} */@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)public void onChildViewAdded(View parent, View child) {if (parent == CustomNestRadioGroup.this) {CompoundButton view = findCheckedView(child);// 尋找子控制項if (view != null) {int id = view.getId();// generates an id if it's missingif (id == View.NO_ID&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {id = View.generateViewId();view.setId(id);}view.setOnCheckedChangeListener(mChildOnCheckedChangeListener);}}if (mOnHierarchyChangeListener != null) {mOnHierarchyChangeListener.onChildViewAdded(parent, child);}}/** * {@inheritDoc} */public void onChildViewRemoved(View parent, View child) {if (parent == CustomNestRadioGroup.this) {CompoundButton view = findCheckedView(child);// 尋找子控制項if (view != null) {view.setOnCheckedChangeListener(null);}}if (mOnHierarchyChangeListener != null) {mOnHierarchyChangeListener.onChildViewRemoved(parent, child);}}}}

這個類是從RadioGroup源碼copy出來進行修改,增加向下遞迴尋找RadioGroup方法即可。代碼有注釋。

二、MainActivity

package com.example.customgroupdemo;import android.os.Bundle;import android.app.Activity;import android.view.Menu;import android.widget.Toast;import com.example.customgroupdemo.CustomNestRadioGroup;import com.example.customgroupdemo.CustomNestRadioGroup.OnCheckedChangeListener;public class MainActivity extends Activity implements OnCheckedChangeListener{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//修改RadioGroup源碼後的自訂控制項,可以尋找RadioGroup裡面不同布局RadioButtonCustomNestRadioGroup CustomRadioGroup = (CustomNestRadioGroup)findViewById(R.id.CustomRadioGroup);if (CustomRadioGroup != null) CustomRadioGroup.setOnCheckedChangeListener(this);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic void onCheckedChanged(CustomNestRadioGroup group, int checkedId) {group.check(checkedId);if (group.getId() == R.id.CustomRadioGroup) {if (checkedId == R.id.radio0) {Toast.makeText(getApplicationContext(), "選擇一", Toast.LENGTH_SHORT).show();}else if (checkedId == R.id.radio1) {Toast.makeText(getApplicationContext(), "選擇二", Toast.LENGTH_SHORT).show();}else if (checkedId == R.id.radio2) {Toast.makeText(getApplicationContext(), "選擇三", Toast.LENGTH_SHORT).show();}}}}

自訂控制項的使用,主要是通過完整的包名加上class名稱來尋找,可以看activity以及xml就能知道怎樣調用自訂控制項。

樣本:com.example.customgroupdemo.CustomNestRadioGroup

三、xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <ScrollView        android:id="@+id/scrollView1"        android:layout_width="match_parent"        android:layout_height="wrap_content" >        <LinearLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            android:orientation="vertical" >            <com.example.customgroupdemo.CustomNestRadioGroup                android:id="@+id/CustomRadioGroup"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:orientation="vertical" >                <TextView                    android:id="@+id/textView1"                    android:layout_width="match_parent"                    android:layout_height="wrap_content"                    android:gravity="center"                    android:text="第一個" />                <LinearLayout                    android:layout_width="305dp"                    android:layout_height="wrap_content"                    android:orientation="horizontal" >                    <RadioButton                        android:id="@+id/radio0"                        android:layout_width="wrap_content"                        android:layout_height="wrap_content"                        android:checked="true"                        android:text="選擇一" />                    <TextView                        android:id="@+id/textView1"                        android:layout_width="match_parent"                        android:layout_height="wrap_content"                        android:gravity="right"                        android:text="第一個" />                </LinearLayout>                <TextView                    android:id="@+id/textView1"                    android:layout_width="match_parent"                    android:layout_height="wrap_content"                    android:gravity="center"                    android:text="第二個" />                <LinearLayout                    android:layout_width="305dp"                    android:layout_height="wrap_content"                    android:orientation="horizontal" >                    <RadioButton                        android:id="@+id/radio1"                        android:layout_width="wrap_content"                        android:layout_height="wrap_content"                        android:text="選擇二" />                    <TextView                        android:id="@+id/textView1"                        android:layout_width="match_parent"                        android:layout_height="wrap_content"                        android:gravity="right"                        android:text="第二個" />                </LinearLayout>                <TextView                    android:id="@+id/textView1"                    android:layout_width="match_parent"                    android:layout_height="wrap_content"                    android:gravity="center"                    android:text="第三個" />                <LinearLayout                    android:layout_width="305dp"                    android:layout_height="wrap_content"                    android:orientation="horizontal" >                    <RadioButton                        android:id="@+id/radio2"                        android:layout_width="wrap_content"                        android:layout_height="wrap_content"                        android:text="選擇三" />                    <TextView                        android:id="@+id/textView1"                        android:layout_width="match_parent"                        android:layout_height="wrap_content"                        android:gravity="right"                        android:text="第三個" />                </LinearLayout>            </com.example.customgroupdemo.CustomNestRadioGroup>        </LinearLayout>    </ScrollView></LinearLayout>
四、看看


歡迎交流學習各種自訂控制項,源碼學習。

轉載請註明出處:單擊此處

歡迎下載測試demo:單擊此處

Android 自訂RadioGroup布局

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.