• 自定义android RadioButton View,添加较为灵活的布局处理方式


    android的RadioButton的使用历来都让人比较头疼,如在布局方面,图案、文字无法分别设置padding等,另外,低版本的android RadioGroup不支持换行排列的RadioButton(此bug在4.4以上貌似已经修复)

    这里我自定义了一个VariedRadioButton,主要的功能优势有:

    1.可以一步添加多个radio button,不需要在xml布局文件中进行多次罗列;

    2.灵活布局:添加text、image的margin等属性,可以自由定义间隔;

    3.灵活布局:自由定义image/text的前后顺序

    4.灵活布局:自由设定radio button的orientation,支持横向和纵向

    5.无需添加响应radio button的oncheckedchanged接口。在需要取值时,直接调用一行代码即可。

    效果如下:

    代码如下:

    主界面:

     1 package cn.carbs.variedradiobutton;
     2 
     3 import android.app.Activity;
     4 import android.os.Bundle;
     5 import android.view.View;
     6 import android.widget.Button;
     7 import cn.carbs.variedradiobutton.view.VariedRadioButton;
     8 
     9 public class MainActivity extends Activity {
    10 
    11     VariedRadioButton variedRadioButton;
    12     Button button;
    13     @Override
    14     protected void onCreate(Bundle savedInstanceState) {
    15         super.onCreate(savedInstanceState);
    16         setContentView(R.layout.activity_main);
    17         variedRadioButton = (VariedRadioButton)findViewById(R.id.v);
    18         button = (Button)findViewById(R.id.button);
    19         button.setOnClickListener(new View.OnClickListener() {
    20             
    21             @Override
    22             public void onClick(View v) {
    23                 variedRadioButton.setSelectedIndex(4);
    24             }
    25         });
    26         
    27         variedRadioButton.setSelectedIndex(3);
    28     }
    29 
    30 
    31 }

    自定义view的代码:

      1 package cn.carbs.variedradiobutton.view;
      2 
      3 import java.util.ArrayList;
      4 
      5 import android.content.Context;
      6 import android.content.res.TypedArray;
      7 import android.graphics.drawable.Drawable;
      8 import android.util.AttributeSet;
      9 import android.util.Log;
     10 import android.util.TypedValue;
     11 import android.view.Gravity;
     12 import android.view.View;
     13 import android.widget.ImageView;
     14 import android.widget.LinearLayout;
     15 import android.widget.TextView;
     16 
     17 import cn.carbs.variedradiobutton.R;
     18 import cn.carbs.variedradiobutton.util.DisplayUtil;
     19 
     20 
     21 public class VariedRadioButton extends LinearLayout implements View.OnClickListener{
     22 
     23     private static final String TAG = "wang";
     24     
     25     private static final int ORDER_IMAGE_FIRST = 0;
     26     private static final int ORDER_TEXT_FIRST = 1;
     27     
     28     private static final int DEFAULT_SELECTED_INDEX = 0;
     29     
     30     private static final float DEFAULT_MARGIN = 0f;
     31     private static final int DEFAULT_ORDER = ORDER_IMAGE_FIRST;
     32     private static final int DEFAULT_ORIENTATION = LinearLayout.HORIZONTAL;
     33     private static final int DEFAULT_NUM = 2;
     34     private static final int DEFAULT_TEXT_COLOR = 0xff000000;
     35     private static final float DEFAULT_TEXT_VIEW_TEXT_SIZE_SP = 16;
     36     
     37     private static final int DEFAULT_TEXTS_RES = 0;
     38     private static final int DEFAULT_IMAGE_RES = 0;
     39     
     40     private Context mContext;
     41     private int mDrawableBackgroundRadioSelected;
     42     private int mDrawableBackgroundRadio;
     43     private Drawable mDrawableBackgroundText;
     44     private float mTextMarginLeft = DEFAULT_MARGIN;
     45     private float mTextMarginRight = DEFAULT_MARGIN;
     46     private float mTextMarginTop = DEFAULT_MARGIN;
     47     private float mTextMarginBottom = DEFAULT_MARGIN;
     48     private float mImageMarginLeft = DEFAULT_MARGIN;
     49     private float mImageMarginRight = DEFAULT_MARGIN;
     50     private float mImageMarginTop = DEFAULT_MARGIN;
     51     private float mImageMarginBottom = DEFAULT_MARGIN;
     52     private float mUnitMarginLeft = DEFAULT_MARGIN;
     53     private float mUnitMarginRight = DEFAULT_MARGIN;
     54     private float mUnitMarginTop = DEFAULT_MARGIN;
     55     private float mUnitMarginBottom = DEFAULT_MARGIN;
     56     
     57     private int mOrder = DEFAULT_ORDER;
     58     private int mOrientation = DEFAULT_ORIENTATION;
     59     private int mNum = DEFAULT_NUM;
     60     private int mTextColor = DEFAULT_TEXT_COLOR;
     61     private float mTextSize = DEFAULT_TEXT_VIEW_TEXT_SIZE_SP;
     62     private int mTextsRes = DEFAULT_TEXTS_RES;
     63     private String[] mTexts;
     64     private ArrayList<ImageView> mImageViews = new ArrayList();
     65     private ArrayList<TextView> mTextViews = new ArrayList();
     66     
     67     private View mContentView = null;
     68     private LinearLayout mContainer = null;
     69     
     70     private Object mTagTextView = new Object();
     71     private Object mTagImageView = new Object();
     72     
     73     private int mSelectedIndex = DEFAULT_SELECTED_INDEX;
     74     
     75     public VariedRadioButton(Context context) {
     76         this(context, null);
     77     }
     78     
     79     public VariedRadioButton(Context context, AttributeSet attrs) {
     80         this(context, attrs, 0);
     81     }
     82     
     83     public VariedRadioButton(Context context, AttributeSet attrs, int defStyle) {
     84         super(context, attrs, defStyle);
     85         mContext = context;
     86         mContentView = inflate(context, R.layout.view_varied_radio_button, this);
     87         mContainer = (LinearLayout)mContentView.findViewById(R.id.container);
     88         
     89         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.variedRadioButton);
     90         
     91         final int count = a.getIndexCount(); 
     92         for (int i = 0; i < count; ++i) { 
     93             int attr = a.getIndex(i); 
     94             switch (attr) {
     95             case R.styleable.variedRadioButton_backgroundRadioSelected: 
     96                 mDrawableBackgroundRadioSelected = a.getResourceId(attr, DEFAULT_IMAGE_RES);
     97                 break; 
     98             case R.styleable.variedRadioButton_backgroundRadio: 
     99                 mDrawableBackgroundRadio = a.getResourceId(attr, DEFAULT_IMAGE_RES);
    100                 break; 
    101             case R.styleable.variedRadioButton_backgroundText: 
    102                 mDrawableBackgroundText  = a.getDrawable(attr); 
    103                 break; 
    104             case R.styleable.variedRadioButton_textMarginLeft: 
    105                 mTextMarginLeft = a.getDimension(attr, DEFAULT_MARGIN);
    106                 break; 
    107             case R.styleable.variedRadioButton_textMarginRight: 
    108                 mTextMarginRight = a.getDimension(attr, DEFAULT_MARGIN);
    109                 break; 
    110             case R.styleable.variedRadioButton_textMarginTop: 
    111                 mTextMarginTop = a.getDimension(attr, DEFAULT_MARGIN);
    112                 break; 
    113             case R.styleable.variedRadioButton_textMarginBottom: 
    114                 mTextMarginBottom = a.getDimension(attr, DEFAULT_MARGIN);
    115                 break; 
    116             case R.styleable.variedRadioButton_imageMarginLeft: 
    117                 mImageMarginLeft = a.getDimension(attr, DEFAULT_MARGIN);
    118                 break; 
    119             case R.styleable.variedRadioButton_imageMarginRight: 
    120                 mImageMarginRight = a.getDimension(attr, DEFAULT_MARGIN);
    121                 break; 
    122             case R.styleable.variedRadioButton_imageMarginTop: 
    123                 mImageMarginTop = a.getDimension(attr, DEFAULT_MARGIN);
    124                 break; 
    125             case R.styleable.variedRadioButton_imageMarginBottom: 
    126                 mImageMarginBottom = a.getDimension(attr, DEFAULT_MARGIN);
    127                 break; 
    128             case R.styleable.variedRadioButton_unitMarginLeft: 
    129                 mUnitMarginLeft = a.getDimension(attr, DEFAULT_MARGIN);
    130                 break; 
    131             case R.styleable.variedRadioButton_unitMarginRight: 
    132                 mUnitMarginRight = a.getDimension(attr, DEFAULT_MARGIN);
    133                 break; 
    134             case R.styleable.variedRadioButton_unitMarginTop: 
    135                 mUnitMarginTop = a.getDimension(attr, DEFAULT_MARGIN);
    136                 break; 
    137             case R.styleable.variedRadioButton_unitMarginBottom: 
    138                 mUnitMarginBottom = a.getDimension(attr, DEFAULT_MARGIN);
    139                 break; 
    140             case R.styleable.variedRadioButton_order: 
    141                 mOrder = a.getInt(attr, DEFAULT_ORDER);
    142                 break; 
    143             case R.styleable.variedRadioButton_radioButtonNum: 
    144                 mNum = a.getInt(attr, DEFAULT_NUM); 
    145                 break; 
    146             case R.styleable.variedRadioButton_contentTextColor:
    147                 mTextColor = a.getColor(attr, DEFAULT_TEXT_COLOR);
    148                 break; 
    149             case R.styleable.variedRadioButton_contentTextSize: 
    150                 mTextSize = DisplayUtil.px2sp(mContext, a.getDimensionPixelSize(attr, DisplayUtil.sp2px(mContext, DEFAULT_TEXT_VIEW_TEXT_SIZE_SP)));
    151                 break; 
    152             case R.styleable.variedRadioButton_optionsOrientation: 
    153                 mOrientation = a.getInt(attr, DEFAULT_ORIENTATION);
    154                 break; 
    155             case R.styleable.variedRadioButton_texts: 
    156                 mTextsRes = a.getResourceId(attr, DEFAULT_TEXTS_RES);
    157                 mTexts = mContext.getResources().getStringArray(mTextsRes);
    158                 break; 
    159             case R.styleable.variedRadioButton_selectedIndex: 
    160                 mSelectedIndex = a.getInt(attr, DEFAULT_SELECTED_INDEX);
    161                 break; 
    162                 
    163             }
    164         }
    165         a.recycle(); 
    166         
    167         mContainer.setOrientation(mOrientation);
    168         LinearLayout.LayoutParams paramsUnit = null;
    169         if(mOrientation == LinearLayout.HORIZONTAL){
    170             paramsUnit = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT);
    171         }else{
    172             paramsUnit = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 0);
    173         }
    174         
    175         paramsUnit.weight = 1;
    176         paramsUnit.leftMargin = (int)mUnitMarginLeft;
    177         paramsUnit.rightMargin = (int)mUnitMarginRight;
    178         paramsUnit.topMargin = (int)mUnitMarginTop;
    179         paramsUnit.bottomMargin = (int)mUnitMarginBottom;
    180         
    181         LinearLayout.LayoutParams paramsImageView = new LinearLayout.LayoutParams(
    182                 LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
    183         paramsImageView.leftMargin = (int)mImageMarginLeft;
    184         paramsImageView.rightMargin = (int)mImageMarginRight;
    185         paramsImageView.topMargin = (int)mImageMarginTop;
    186         paramsImageView.bottomMargin = (int)mImageMarginBottom;
    187         
    188         LinearLayout.LayoutParams paramsTextView = new LinearLayout.LayoutParams(
    189                 LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
    190         paramsTextView.leftMargin = (int)mTextMarginLeft;
    191         paramsTextView.rightMargin = (int)mTextMarginRight;
    192         paramsTextView.topMargin = (int)mTextMarginTop;
    193         paramsTextView.bottomMargin = (int)mTextMarginBottom;
    194         
    195         for(int n = 0; n < mNum; n++){
    196             
    197             LinearLayout ll = new LinearLayout(mContext);
    198             ll.setOrientation(LinearLayout.HORIZONTAL);
    199             ll.setGravity(Gravity.CENTER_VERTICAL);
    200             
    201             ImageView image = new ImageView(mContext);
    202             image.setBackgroundResource(mDrawableBackgroundRadio);
    203             image.setLayoutParams(paramsImageView);
    204             image.setTag(mTagImageView);
    205             
    206             TextView text = new TextView(mContext);
    207             text.setGravity(Gravity.CENTER);
    208             if(n < mTexts.length){
    209                 text.setText(mTexts[n]);
    210             }
    211             text.setLayoutParams(paramsTextView);
    212             text.setTag(mTagTextView);
    213             text.setTextSize(mTextSize);
    214             text.setTextColor(mTextColor);
    215             
    216             if(mOrder == ORDER_IMAGE_FIRST){
    217                 ll.addView(image);
    218                 ll.addView(text);
    219             }else{
    220                 ll.addView(text);
    221                 ll.addView(image);
    222             }
    223             ll.setTag(n);
    224             ll.setOnClickListener(this);
    225             
    226             mImageViews.add(image);
    227             mTextViews.add(text);
    228             mContainer.addView(ll, paramsUnit);
    229         }
    230         mContainer.setWeightSum(mNum);
    231         setSelectedIndex(mSelectedIndex);
    232     }
    233     
    234     public void setRadioButtonNum(int num){
    235         mNum = num;
    236     }
    237     
    238     public void setTextsRes(int textsRes){
    239         mTextsRes = textsRes;
    240         mTexts = mContext.getResources().getStringArray(mTextsRes);
    241     }
    242     
    243     public void setTexts(String[] texts){
    244         mTexts = texts;
    245     }
    246     
    247     public void setSelectedIndex(int selectedIndex){
    248         if(selectedIndex >= 0 && selectedIndex < mNum){
    249             refreshView(selectedIndex);
    250         }else{
    251             
    252         }
    253     }
    254     
    255     public int getSelectedIndex(){
    256         return mSelectedIndex;
    257     }
    258 
    259     @Override
    260     public void onClick(View v) {
    261         Integer index = (Integer)v.getTag();
    262         if(index != null){
    263             refreshView(index);
    264         }else{
    265             throw new IllegalArgumentException("need to set a tag to LinearLayout element");
    266         }
    267     }
    268     
    269     private void refreshView(int selectedIndex){
    270         mSelectedIndex = selectedIndex;
    271         LinearLayout clickedLL = null;
    272         ImageView image = null;
    273         for(int i = 0; i < mNum; i++){
    274             clickedLL = (LinearLayout)this.findViewWithTag(i);
    275             image = (ImageView)clickedLL.findViewWithTag(mTagImageView);
    276             if(i == selectedIndex){
    277                 image.setBackgroundResource(mDrawableBackgroundRadioSelected);
    278             }else{
    279                 image.setBackgroundResource(mDrawableBackgroundRadio);
    280             }
    281         }
    282     }
    283     
    284 }

    布局文件:

    activity_main.xml

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:app="http://schemas.android.com/apk/res/cn.carbs.variedradiobutton"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:orientation="vertical"
     6     android:paddingBottom="@dimen/activity_vertical_margin"
     7     android:paddingLeft="@dimen/activity_horizontal_margin"
     8     android:paddingRight="@dimen/activity_horizontal_margin"
     9     android:paddingTop="@dimen/activity_vertical_margin" >
    10 
    11     <cn.carbs.variedradiobutton.view.VariedRadioButton
    12         android:id="@+id/v"
    13         android:layout_width="match_parent"
    14         android:layout_height="wrap_content"
    15         android:background="#33333333"
    16         android:text="@string/hello_world"
    17         app:backgroundRadio="@drawable/button_unchecked"
    18         app:backgroundRadioSelected="@drawable/button_checked"
    19         app:backgroundText="#333333"
    20         app:imageMarginLeft="30dp"
    21         app:optionsOrientation="horizontal"
    22         app:order="imageFirst"
    23         app:radioButtonNum="5"
    24         app:selectedIndex="1"
    25         app:textMarginLeft="0dp"
    26         app:texts="@array/city" />
    27 
    28     <Button
    29         android:id="@+id/button"
    30         android:layout_width="wrap_content"
    31         android:layout_height="wrap_content"
    32         android:text="button" />
    33 
    34 </LinearLayout>

    view_varied_radio_button.xml :

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:id="@+id/container"
     4     android:orientation="horizontal"
     5     android:layout_width="match_parent"
     6     android:layout_height="wrap_content"
     7     android:gravity="center" >
     8 
     9 
    10 </LinearLayout>

    自定义属性:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <resources>
     3 
     4     <declare-styleable name="variedRadioButton">
     5         <attr name="backgroundRadio" />
     6         <attr name="backgroundRadioSelected" />
     7         <attr name="radioButtonNum" />
     8         <attr name="backgroundText" />
     9         <attr name="order" />
    10         <attr name="contentTextColor" />
    11         <attr name="contentTextSize" />
    12         <attr name="textMarginLeft" />
    13         <attr name="textMarginRight" />
    14         <attr name="textMarginTop" />
    15         <attr name="textMarginBottom" />
    16         <attr name="imageMarginLeft" />
    17         <attr name="imageMarginRight" />
    18         <attr name="imageMarginTop" />
    19         <attr name="imageMarginBottom" />
    20         <attr name="unitMarginLeft" />
    21         <attr name="unitMarginRight" />
    22         <attr name="unitMarginTop" />
    23         <attr name="unitMarginBottom" />
    24         <attr name="texts" />
    25         <attr name="optionsOrientation">
    26             <enum name="horizontal" value="0" />
    27                <enum name="vertical" value="1" />
    28         </attr>
    29         <attr name="selectedIndex" />
    30     </declare-styleable>
    31     
    32     <attr name="backgroundRadioSelected" format="reference|color" />
    33     <attr name="backgroundRadio" format="reference|color" />
    34     <attr name="radioButtonNum" format="reference|integer" />
    35     <attr name="backgroundText" format="reference|color" />
    36     <attr name="contentTextColor" format="reference|color" />
    37     <attr name="contentTextSize" format="reference|dimension" />
    38     <attr name="texts" format="reference" />
    39     <attr name="textMarginLeft" format="reference|dimension" />
    40     <attr name="textMarginRight" format="reference|dimension" />
    41     <attr name="textMarginTop" format="reference|dimension" />
    42     <attr name="textMarginBottom" format="reference|dimension" />
    43     <attr name="imageMarginLeft" format="reference|dimension" />
    44     <attr name="imageMarginRight" format="reference|dimension" />
    45     <attr name="imageMarginTop" format="reference|dimension" />
    46     <attr name="imageMarginBottom" format="reference|dimension" />
    47     
    48     <attr name="unitMarginLeft" format="reference|dimension" />
    49     <attr name="unitMarginRight" format="reference|dimension" />
    50     <attr name="unitMarginTop" format="reference|dimension" />
    51     <attr name="unitMarginBottom" format="reference|dimension" />
    52     
    53     <attr name="selectedIndex" format="reference|integer" />
    54     
    55     <attr name="order">
    56         <enum name="imageFirst" value="0" />
    57         <enum name="textFirst" value="1" />
    58     </attr>
    59 
    60 </resources>

    string资源:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    
        <string name="app_name">VariedRadioButton</string>
        <string name="action_settings">Settings</string>
        <string name="hello_world">Hello world!</string>
        <string-array name="city">
            <item>中国</item>
            <item>美国</item>
            <item>俄罗斯</item>
            <item>英国</item>
            <item>德国</item>
        </string-array>
    </resources>

    尺寸转换工具类:(此类是在网上找的资源)

     1 package cn.carbs.variedradiobutton.util;
     2 
     3 import android.content.Context;
     4 
     5 /**
     6  * dp、sp 转换为 px 的工具类
     7  */ 
     8 public class DisplayUtil { 
     9     /**
    10      * 将px值转换为dip或dp值,保证尺寸大小不变
    11      * 
    12      * @param pxValue
    13      * @param scale
    14      * @return
    15      */ 
    16     public static int px2dip(Context context, float pxValue) { 
    17         final float scale = context.getResources().getDisplayMetrics().density; 
    18         return (int) (pxValue / scale + 0.5f); 
    19     } 
    20    
    21     /**
    22      * 将dip或dp值转换为px值,保证尺寸大小不变
    23      * 
    24      * @param dipValue
    25      * @param scale
    26      * @return
    27      */ 
    28     public static int dip2px(Context context, float dipValue) { 
    29         final float scale = context.getResources().getDisplayMetrics().density; 
    30         return (int) (dipValue * scale + 0.5f); 
    31     } 
    32    
    33     /**
    34      * 将px值转换为sp值,保证文字大小不变
    35      * 
    36      * @param pxValue
    37      * @param fontScale
    38      * @return
    39      */ 
    40     public static int px2sp(Context context, float pxValue) { 
    41         final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 
    42         return (int) (pxValue / fontScale + 0.5f); 
    43     } 
    44    
    45     /**
    46      * 将sp值转换为px值,保证文字大小不变
    47      * 
    48      * @param spValue
    49      * @param fontScale
    50      * @return
    51      */ 
    52     public static int sp2px(Context context, float spValue) { 
    53         final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 
    54         return (int) (spValue * fontScale + 0.5f); 
    55     } 
    56 }

    使用方法:

    1.在xml布局文件中:由于用到了自定义属性,因此需要添加命名空间xmlns:app="http://schemas.android.com/apk/res/cn.carbs.variedradiobutton"

    <cn.carbs.variedradiobutton.view.VariedRadioButton
    android:id="@+id/v"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#33333333"
    android:text="@string/hello_world"
    app:backgroundRadio="@drawable/button_unchecked"
    app:backgroundRadioSelected="@drawable/button_checked"
    app:backgroundText="#333333"
    app:imageMarginLeft="30dp"
    app:optionsOrientation="horizontal"
    app:order="imageFirst"
    app:radioButtonNum="5"
    app:selectedIndex="1"
    app:textMarginLeft="0dp"
    app:texts="@array/city" />

    原理很简单:

    VariedRadioButton继承了ViewGroup(LinearLayout),通过代码添加成对的imageview+textview来实现radiobutton的效果。

    主要属性的说明:
    app:backgroundRadio 定义未被选中的radiobutton的背景
    app:backgroundRadioSelected 定义已被选中的radiobutton的背景
    app:backgroundText 定义textview的背景
    app:imageMarginLeft 定义imageview距离左侧控件间距
    app:order="imageFirst" imageview在左
    app:order="textFirst" 则是textview在左
    app:radioButtonNum="5" 一共包含多少个“radiobutton”
    app:selectedIndex="1" 设置初始的选中的按钮,从0开始
    app:texts="@array/city" 定义所有的“radiobutton”使用的string资源,如果array的length小于num,则后面的radiobutton的文字设置为空
  • 相关阅读:
    Linux 下编译hello world 的C 语言程序
    C语言实现二维数组操作--元素个数确定
    Linux Eclipse安装和配置命令行(jre、jdk)
    段错误bug的调试
    fopen与open的区别
    同样的c代码,为何在windows下和linux下执行结果不一样?
    VIM快捷键
    浅谈C中的wprintf和宽字符显示
    Know More About Oracle Row Lock
    【教学视频】Maclean教你一步一步使用Vbox在Linux 5上安装Oracle 11gR2 RAC
  • 原文地址:https://www.cnblogs.com/carbs/p/5142001.html
Copyright © 2020-2023  润新知