自定义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接口。在需要取值时,直接调用一行代码即可。
效果如下:

代码如下:
主界面:
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,添加较为灵活的布局处理方式的更多相关文章
- Android中View的layout mechanism(布局机制)
layout mechanism Android中View的layout mechanism主要分为两个阶段:measure阶段和layout阶段.layout mechanism按照一定的顺序进行, ...
- android 给view添加阴影
1.方法一: 使用 CardView 布局 <android.support.v7.widget.CardView xmlns:android="http://schemas.andr ...
- Android中View绘制优化之一---- 优化布局层次
本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 前言,竟然是翻译,当然得弄的有板有眼. 照着大作家格式来咯 , - - . 译序 最近一直在做锁屏界面,之前也 ...
- Android ListView中添加不同的多种布局
最近做项目要使用ListView加载不同的布局,由于自己写的代码不能贴出,故找了一篇自认为比较好的blog给分享出来,希望对用到此项技术的同学有点帮助. http://logc.at/2011/10/ ...
- Android中自定义样式与View的构造函数中的第三个参数defStyle的意义
零.序 一.自定义Style 二.在XML中为属性声明属性值 1. 在layout中定义属性 2. 设置Style 3. 通过Theme指定 三.在运行时获取属性值 1. View的第三个构造函数的第 ...
- 【转】Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布 ...
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
Android中View的绘制过程 onMeasure方法简述 附有自定义View例子 Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android fr ...
- Android 如何动态添加 View 并显示在指定位置。
引子 最近,在做产品的需求的时候,遇到 PM 要求在某个按钮上添加一个新手引导动画,引导用户去点击.作为 RD,我哗啦啦的就写好相关逻辑了.自测完成后,提测,PM Review 效果. 看完后,PM ...
- android显示通知栏Notification以及自定义Notification的View
遇到的最大的问题是监听不到用户清除通知栏的广播.所以是不能监听到的. 自定义通知栏的View,然后service运行时更改notification的信息. /** * Show a notificat ...
随机推荐
- sqlplus实现上下翻页设置
环境: 操作系统:red hat 5.8 OS 数据库:oracle 11g 11.2.0.1 安装软件:IO-Tty-1.07.tar. Term-ReadLine-Gnu-1.16.tar.uni ...
- 备份数据库的时候设置 BufferCount 选项不正确导致 out of memory 的情况
备份数据库的时候设置 BufferCount 选项不正确导致 out of memory 的情况 今天群里面的东辉兄跟我说备份生产数据库的时候报错 环境: 32位的SQLSERVER2008 机器有1 ...
- Google被墙 Android开发工具下载地址
Android开发环境的官网下载地址 可以直接下载 (1)Adt Bundle Platform Package Size MD5 Checksum Windows 32-bit adt-bundle ...
- 安装完成Windows服务后自动打开
使用DOS进程开启服务 设置serviceProcessInstaller1控件的Account属性为“LocalSystem”设置serviceInstaller1控件的StartType属性为&q ...
- jquery bind、delegate、live、on的区别及联系
jquery bind.delegate.live.on的区别及联系 概述 jquery提供了好几个API都可以实现事件绑定, 如 delegate, live , bind 等, 可是有没有疑惑这几 ...
- Nginx学习笔记(六) 源码分析&启动过程
Nginx的启动过程 主要介绍Nginx的启动过程,可以在/core/nginx.c中找到Nginx的主函数main(),那么就从这里开始分析Nginx的启动过程. 涉及到的基本函数 源码: /* * ...
- ybutton 高端大气上档次华丽的按钮特效
小菜偶然在某网站中看到一款非常华丽的按钮特效,感觉十分有必要抄袭下来,以备日后使用. 简单描述一下按钮的效果:鼠标移到按钮上的时候,会出现灯光闪过的效果,非常的高端. 但遗憾的,这么牛逼的效果,仅仅兼 ...
- 免费好用的web应用托管平台-续
上一篇博客给大家推荐了目前处于免费阶段的PAAS平台,可以托管各种应用,大家反响很不错,说明大家还是很需要和认可这个免费托管各种web应用的京东云擎平台.但是很多用户还是很担心未来可能还是会收费,对于 ...
- T4模板TextTemplatingFileGenerator和TextTemplatingFilePreprocessor区别
最近做一个项目,需要根据数据库表生成对应的实体类,于是想到了代码生成器.查阅了Nvelocity.T4.RazorEngine,对于一个微软技术派,觉得还是T4最亲切,使用简单,功能强大. 在尝试使用 ...
- node.js cluster多进程、负载均衡和平滑重启
1 cluster多进程 cluster经过好几代的发展,现在已经比较好使了.利用cluster,可以自动完成子进程worker分配request的事情,就不再需要自己写代码在master进程中rob ...