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接口。在需要取值时,直接调用一行代码即可。

效果如下:

代码如下:

主界面:

 package cn.carbs.variedradiobutton;

 import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import cn.carbs.variedradiobutton.view.VariedRadioButton; public class MainActivity extends Activity { VariedRadioButton variedRadioButton;
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
variedRadioButton = (VariedRadioButton)findViewById(R.id.v);
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
variedRadioButton.setSelectedIndex(4);
}
}); variedRadioButton.setSelectedIndex(3);
} }

自定义view的代码:

 package cn.carbs.variedradiobutton.view;

 import java.util.ArrayList;

 import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import cn.carbs.variedradiobutton.R;
import cn.carbs.variedradiobutton.util.DisplayUtil; public class VariedRadioButton extends LinearLayout implements View.OnClickListener{ private static final String TAG = "wang"; private static final int ORDER_IMAGE_FIRST = 0;
private static final int ORDER_TEXT_FIRST = 1; private static final int DEFAULT_SELECTED_INDEX = 0; private static final float DEFAULT_MARGIN = 0f;
private static final int DEFAULT_ORDER = ORDER_IMAGE_FIRST;
private static final int DEFAULT_ORIENTATION = LinearLayout.HORIZONTAL;
private static final int DEFAULT_NUM = 2;
private static final int DEFAULT_TEXT_COLOR = 0xff000000;
private static final float DEFAULT_TEXT_VIEW_TEXT_SIZE_SP = 16; private static final int DEFAULT_TEXTS_RES = 0;
private static final int DEFAULT_IMAGE_RES = 0; private Context mContext;
private int mDrawableBackgroundRadioSelected;
private int mDrawableBackgroundRadio;
private Drawable mDrawableBackgroundText;
private float mTextMarginLeft = DEFAULT_MARGIN;
private float mTextMarginRight = DEFAULT_MARGIN;
private float mTextMarginTop = DEFAULT_MARGIN;
private float mTextMarginBottom = DEFAULT_MARGIN;
private float mImageMarginLeft = DEFAULT_MARGIN;
private float mImageMarginRight = DEFAULT_MARGIN;
private float mImageMarginTop = DEFAULT_MARGIN;
private float mImageMarginBottom = DEFAULT_MARGIN;
private float mUnitMarginLeft = DEFAULT_MARGIN;
private float mUnitMarginRight = DEFAULT_MARGIN;
private float mUnitMarginTop = DEFAULT_MARGIN;
private float mUnitMarginBottom = DEFAULT_MARGIN; private int mOrder = DEFAULT_ORDER;
private int mOrientation = DEFAULT_ORIENTATION;
private int mNum = DEFAULT_NUM;
private int mTextColor = DEFAULT_TEXT_COLOR;
private float mTextSize = DEFAULT_TEXT_VIEW_TEXT_SIZE_SP;
private int mTextsRes = DEFAULT_TEXTS_RES;
private String[] mTexts;
private ArrayList<ImageView> mImageViews = new ArrayList();
private ArrayList<TextView> mTextViews = new ArrayList(); private View mContentView = null;
private LinearLayout mContainer = null; private Object mTagTextView = new Object();
private Object mTagImageView = new Object(); private int mSelectedIndex = DEFAULT_SELECTED_INDEX; public VariedRadioButton(Context context) {
this(context, null);
} public VariedRadioButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public VariedRadioButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
mContentView = inflate(context, R.layout.view_varied_radio_button, this);
mContainer = (LinearLayout)mContentView.findViewById(R.id.container); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.variedRadioButton); final int count = a.getIndexCount();
for (int i = 0; i < count; ++i) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.variedRadioButton_backgroundRadioSelected:
mDrawableBackgroundRadioSelected = a.getResourceId(attr, DEFAULT_IMAGE_RES);
break;
case R.styleable.variedRadioButton_backgroundRadio:
mDrawableBackgroundRadio = a.getResourceId(attr, DEFAULT_IMAGE_RES);
break;
case R.styleable.variedRadioButton_backgroundText:
mDrawableBackgroundText = a.getDrawable(attr);
break;
case R.styleable.variedRadioButton_textMarginLeft:
mTextMarginLeft = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_textMarginRight:
mTextMarginRight = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_textMarginTop:
mTextMarginTop = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_textMarginBottom:
mTextMarginBottom = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_imageMarginLeft:
mImageMarginLeft = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_imageMarginRight:
mImageMarginRight = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_imageMarginTop:
mImageMarginTop = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_imageMarginBottom:
mImageMarginBottom = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_unitMarginLeft:
mUnitMarginLeft = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_unitMarginRight:
mUnitMarginRight = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_unitMarginTop:
mUnitMarginTop = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_unitMarginBottom:
mUnitMarginBottom = a.getDimension(attr, DEFAULT_MARGIN);
break;
case R.styleable.variedRadioButton_order:
mOrder = a.getInt(attr, DEFAULT_ORDER);
break;
case R.styleable.variedRadioButton_radioButtonNum:
mNum = a.getInt(attr, DEFAULT_NUM);
break;
case R.styleable.variedRadioButton_contentTextColor:
mTextColor = a.getColor(attr, DEFAULT_TEXT_COLOR);
break;
case R.styleable.variedRadioButton_contentTextSize:
mTextSize = DisplayUtil.px2sp(mContext, a.getDimensionPixelSize(attr, DisplayUtil.sp2px(mContext, DEFAULT_TEXT_VIEW_TEXT_SIZE_SP)));
break;
case R.styleable.variedRadioButton_optionsOrientation:
mOrientation = a.getInt(attr, DEFAULT_ORIENTATION);
break;
case R.styleable.variedRadioButton_texts:
mTextsRes = a.getResourceId(attr, DEFAULT_TEXTS_RES);
mTexts = mContext.getResources().getStringArray(mTextsRes);
break;
case R.styleable.variedRadioButton_selectedIndex:
mSelectedIndex = a.getInt(attr, DEFAULT_SELECTED_INDEX);
break; }
}
a.recycle(); mContainer.setOrientation(mOrientation);
LinearLayout.LayoutParams paramsUnit = null;
if(mOrientation == LinearLayout.HORIZONTAL){
paramsUnit = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT);
}else{
paramsUnit = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 0);
} paramsUnit.weight = 1;
paramsUnit.leftMargin = (int)mUnitMarginLeft;
paramsUnit.rightMargin = (int)mUnitMarginRight;
paramsUnit.topMargin = (int)mUnitMarginTop;
paramsUnit.bottomMargin = (int)mUnitMarginBottom; LinearLayout.LayoutParams paramsImageView = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
paramsImageView.leftMargin = (int)mImageMarginLeft;
paramsImageView.rightMargin = (int)mImageMarginRight;
paramsImageView.topMargin = (int)mImageMarginTop;
paramsImageView.bottomMargin = (int)mImageMarginBottom; LinearLayout.LayoutParams paramsTextView = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
paramsTextView.leftMargin = (int)mTextMarginLeft;
paramsTextView.rightMargin = (int)mTextMarginRight;
paramsTextView.topMargin = (int)mTextMarginTop;
paramsTextView.bottomMargin = (int)mTextMarginBottom; for(int n = 0; n < mNum; n++){ LinearLayout ll = new LinearLayout(mContext);
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.setGravity(Gravity.CENTER_VERTICAL); ImageView image = new ImageView(mContext);
image.setBackgroundResource(mDrawableBackgroundRadio);
image.setLayoutParams(paramsImageView);
image.setTag(mTagImageView); TextView text = new TextView(mContext);
text.setGravity(Gravity.CENTER);
if(n < mTexts.length){
text.setText(mTexts[n]);
}
text.setLayoutParams(paramsTextView);
text.setTag(mTagTextView);
text.setTextSize(mTextSize);
text.setTextColor(mTextColor); if(mOrder == ORDER_IMAGE_FIRST){
ll.addView(image);
ll.addView(text);
}else{
ll.addView(text);
ll.addView(image);
}
ll.setTag(n);
ll.setOnClickListener(this); mImageViews.add(image);
mTextViews.add(text);
mContainer.addView(ll, paramsUnit);
}
mContainer.setWeightSum(mNum);
setSelectedIndex(mSelectedIndex);
} public void setRadioButtonNum(int num){
mNum = num;
} public void setTextsRes(int textsRes){
mTextsRes = textsRes;
mTexts = mContext.getResources().getStringArray(mTextsRes);
} public void setTexts(String[] texts){
mTexts = texts;
} public void setSelectedIndex(int selectedIndex){
if(selectedIndex >= 0 && selectedIndex < mNum){
refreshView(selectedIndex);
}else{ }
} public int getSelectedIndex(){
return mSelectedIndex;
} @Override
public void onClick(View v) {
Integer index = (Integer)v.getTag();
if(index != null){
refreshView(index);
}else{
throw new IllegalArgumentException("need to set a tag to LinearLayout element");
}
} private void refreshView(int selectedIndex){
mSelectedIndex = selectedIndex;
LinearLayout clickedLL = null;
ImageView image = null;
for(int i = 0; i < mNum; i++){
clickedLL = (LinearLayout)this.findViewWithTag(i);
image = (ImageView)clickedLL.findViewWithTag(mTagImageView);
if(i == selectedIndex){
image.setBackgroundResource(mDrawableBackgroundRadioSelected);
}else{
image.setBackgroundResource(mDrawableBackgroundRadio);
}
}
} }

布局文件:

activity_main.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/cn.carbs.variedradiobutton"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" > <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" /> <Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button" /> </LinearLayout>

view_varied_radio_button.xml :

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center" > </LinearLayout>

自定义属性:

 <?xml version="1.0" encoding="utf-8"?>
<resources> <declare-styleable name="variedRadioButton">
<attr name="backgroundRadio" />
<attr name="backgroundRadioSelected" />
<attr name="radioButtonNum" />
<attr name="backgroundText" />
<attr name="order" />
<attr name="contentTextColor" />
<attr name="contentTextSize" />
<attr name="textMarginLeft" />
<attr name="textMarginRight" />
<attr name="textMarginTop" />
<attr name="textMarginBottom" />
<attr name="imageMarginLeft" />
<attr name="imageMarginRight" />
<attr name="imageMarginTop" />
<attr name="imageMarginBottom" />
<attr name="unitMarginLeft" />
<attr name="unitMarginRight" />
<attr name="unitMarginTop" />
<attr name="unitMarginBottom" />
<attr name="texts" />
<attr name="optionsOrientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
</attr>
<attr name="selectedIndex" />
</declare-styleable> <attr name="backgroundRadioSelected" format="reference|color" />
<attr name="backgroundRadio" format="reference|color" />
<attr name="radioButtonNum" format="reference|integer" />
<attr name="backgroundText" format="reference|color" />
<attr name="contentTextColor" format="reference|color" />
<attr name="contentTextSize" format="reference|dimension" />
<attr name="texts" format="reference" />
<attr name="textMarginLeft" format="reference|dimension" />
<attr name="textMarginRight" format="reference|dimension" />
<attr name="textMarginTop" format="reference|dimension" />
<attr name="textMarginBottom" format="reference|dimension" />
<attr name="imageMarginLeft" format="reference|dimension" />
<attr name="imageMarginRight" format="reference|dimension" />
<attr name="imageMarginTop" format="reference|dimension" />
<attr name="imageMarginBottom" format="reference|dimension" /> <attr name="unitMarginLeft" format="reference|dimension" />
<attr name="unitMarginRight" format="reference|dimension" />
<attr name="unitMarginTop" format="reference|dimension" />
<attr name="unitMarginBottom" format="reference|dimension" /> <attr name="selectedIndex" format="reference|integer" /> <attr name="order">
<enum name="imageFirst" value="0" />
<enum name="textFirst" value="1" />
</attr> </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>

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

 package cn.carbs.variedradiobutton.util;

 import android.content.Context;

 /**
* dp、sp 转换为 px 的工具类
*/
public class DisplayUtil {
/**
* 将px值转换为dip或dp值,保证尺寸大小不变
*
* @param pxValue
* @param scale
* @return
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
} /**
* 将dip或dp值转换为px值,保证尺寸大小不变
*
* @param dipValue
* @param scale
* @return
*/
public static int dip2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
} /**
* 将px值转换为sp值,保证文字大小不变
*
* @param pxValue
* @param fontScale
* @return
*/
public static int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
} /**
* 将sp值转换为px值,保证文字大小不变
*
* @param spValue
* @param fontScale
* @return
*/
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
}

使用方法:

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的文字设置为空

自定义android RadioButton View,添加较为灵活的布局处理方式的更多相关文章

  1. Android中View的layout mechanism(布局机制)

    layout mechanism Android中View的layout mechanism主要分为两个阶段:measure阶段和layout阶段.layout mechanism按照一定的顺序进行, ...

  2. android 给view添加阴影

    1.方法一: 使用 CardView 布局 <android.support.v7.widget.CardView xmlns:android="http://schemas.andr ...

  3. Android中View绘制优化之一---- 优化布局层次

    本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 前言,竟然是翻译,当然得弄的有板有眼. 照着大作家格式来咯 , - - . 译序 最近一直在做锁屏界面,之前也 ...

  4. Android ListView中添加不同的多种布局

    最近做项目要使用ListView加载不同的布局,由于自己写的代码不能贴出,故找了一篇自认为比较好的blog给分享出来,希望对用到此项技术的同学有点帮助. http://logc.at/2011/10/ ...

  5. Android中自定义样式与View的构造函数中的第三个参数defStyle的意义

    零.序 一.自定义Style 二.在XML中为属性声明属性值 1. 在layout中定义属性 2. 设置Style 3. 通过Theme指定 三.在运行时获取属性值 1. View的第三个构造函数的第 ...

  6. 【转】Android中View的绘制过程 onMeasure方法简述 附有自定义View例子

    Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布 ...

  7. Android中View的绘制过程 onMeasure方法简述 附有自定义View例子

    Android中View的绘制过程 onMeasure方法简述 附有自定义View例子 Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android fr ...

  8. Android 如何动态添加 View 并显示在指定位置。

    引子 最近,在做产品的需求的时候,遇到 PM 要求在某个按钮上添加一个新手引导动画,引导用户去点击.作为 RD,我哗啦啦的就写好相关逻辑了.自测完成后,提测,PM Review 效果. 看完后,PM ...

  9. android显示通知栏Notification以及自定义Notification的View

    遇到的最大的问题是监听不到用户清除通知栏的广播.所以是不能监听到的. 自定义通知栏的View,然后service运行时更改notification的信息. /** * Show a notificat ...

随机推荐

  1. JQuery学习(选择器-基本-*)

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  2. 【概念笔记】JAVA基础 - part1

    IT`huhui前言录 这是自己对JAVA基础的一个小总结,会不断完善.因为时间仓促的原因. 每学习一段时间,停下来,静心总结一下,甚好.停停走,走走停,一往无前,不摔倒. 一些链接里面是我看到一些人 ...

  3. C#设计模式(17)——观察者模式(Observer Pattern)

    一.引言 在现实生活中,处处可见观察者模式,例如,微信中的订阅号,订阅博客和QQ微博中关注好友,这些都属于观察者模式的应用.在这一章将分享我对观察者模式的理解,废话不多说了,直接进入今天的主题. 二. ...

  4. Nim教程【二】

    第一篇教程1秒内就被管理员从首页踢掉了 管理员嫌内容太少,没有含金量,这次多写一些. 这应该是国内第一个关于Nim入门的系列教程 好,闲话休提,言归正传 Nim介绍 Nim代码会编译成C语言的代码,再 ...

  5. 记一次https访问握手失败(handshake failure)

    文章作者:luxianghao 文章来源:http://www.cnblogs.com/luxianghao/p/6239518.html  转载请注明,谢谢合作. 免责声明:文章内容仅代表个人观点, ...

  6. paip. java的 函数式编程 大法

    paip. java的 函数式编程 大法 Java 语言中常被忽视的一个方面是它被归类为一种命令式(imperative)编程语言.命令式编程虽然由于与 Java 语言的关联而相当普及,但是并不是惟一 ...

  7. EXCEL VBA入门篇之代码应用基础

  8. 通过swap代码分析C语言指针在汇编级别的实现

    我们先用C语言写一个交换两个数的代码: void swap(int *a, int *b){ int temp = *a; *a = *b; *b = temp; } int main(void) { ...

  9. IOS开发之控件篇UITabBarControllor第一章 - 介绍

    UITabBarControllor的基本样子 官方有个图介绍这个TabBar的结构,我们先来看看这个结构图 --------------------------------------------- ...

  10. 如何处理Android SDK无法更新问题?

    在Android开发中,最痛苦的事情就是相关库升级后,Android SDK太低,跑步起来,最最痛苦的事情就是,想更新,却因大天朝的一墙之隔,愣是没法更新.遇到这种情况怎么办呢?小编和大家分享一个解决 ...