自定义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 ...
随机推荐
- C#设计模式(15)——命令模式(Command Pattern)
一.前言 之前一直在忙于工作上的事情,关于设计模式系列一直没更新,最近项目中发现,对于设计模式的了解是必不可少的,当然对于设计模式的应用那更是重要,可以说是否懂得应用设计模式在项目中是衡量一个程序员的 ...
- ArcMap 连接SDE 出错“Failed to connect to the specified server. Entry for SDE instance no found in services file.”
问题描述 环境: ARCMAP 10.0 ARCSDE FOR ORACLE 10.0 在通过用ArcMap 连接ORACLE SDE时出现上面的错. 解决方式 在 C:\Windows\Sy ...
- javascript图片懒加载与预加载的分析
javascript图片懒加载与预加载的分析 懒加载与预加载的基本概念. 懒加载也叫延迟加载:前一篇文章有介绍:JS图片延迟加载 延迟加载图片或符合某些条件时才加载某些图片. 预加载:提前加载图片, ...
- js随机点名
定时器案例. <!-- Author: XiaoWen Create a file: 2016-12-08 12:27:32 Last modified: 2016-12-08 12:51:59 ...
- 在sublime text 中的Emmet快捷键动态图演示
Emmet的前身是大名鼎鼎的Zen coding,如果你从事Web前端开发的话,对该插件一定不会陌生.它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,比如下面的演示: ...
- Atiti.ui原理与gui理论
Atiti.ui原理与gui理论 1. 概论2 2. ui的类型2 2.1. RMGUI vs IMGUI2 2.2. Cli2 2.3. Gui2 2.4. Nui natural user int ...
- iOS开发-UITextView根据内容自适应高度
UITextView作为内容文本输入区域,有的时候我们需要根据内容动态改变文本区域的高度,效果如下: 定义UITextView,实现UITextViewDelegate: -(UITextView * ...
- javaweb学习总结(二十)——JavaBean总结
一.什么是JavaBean JavaBean是一个遵循特定写法的Java类,它通常具有如下特点: 这个Java类必须具有一个无参的构造函数 属性必须私有化. 私有化的属性必须通过public类型的方法 ...
- 解决pageControl页面设置无效问题
废话不多说,先上代码 1.添加pageViewControl - (void)addPageControl { UIPageControl *pageControl = [[UIPageControl ...
- ASP.NET Web API中的参数绑定总结
ASP.NET Web API中的action参数类型可以分为简单类型和复杂类型. HttpResponseMessage Put(int id, Product item) id是int类型,是简单 ...