可能是一直都在做Web的富客户端开发的缘故吧,在接触Android之后,发现其控件实在惨不忍睹(不知道是否说得过于偏激),我所说的惨不忍睹的意思不是说控件难看,Android的控件非常漂亮,这是我们公司公认的,但是最大的缺点在于控件功能非常弱小。弱小得一个Radio只能放一个text,而没有value(key)可以存放。这就是为什么我说惨不忍睹的原因。
但是这不能怪google,毕竟才刚刚发展起来,Android提供的只是一个最基本的控件实现,而非一个完整、强大的实现。可幸的是,Android提供了自定义控件的实现。有了自定义控件,我们就可以再Android的基础控件上实现我们想要的功能了。经过一天的摸索,我终于实现了我第一个自定义的组合控件——RadioButton组合RadioGroup!
下面我将带领大家进入Android自定义控件的世界。如果觉得我的文章能够帮助大家的话,请大方留下你的一些话语。因为你们的留言是我分享经验的精神源泉!谢谢!
1、设置自定义控件:Android自带的RadioButton只能存放text,这不符合我们的需求,我们需要一个可以同时存放key-value对应的键值。所以我们要编写一个自定义控件能存放key-value。
设计思路:新建一个类叫org.kandy.view.RadioButton,继承自android.wedget.RadioButton,重写父类的所有构造方法。这样我们就实现了一个跟父类一摸一样的控件。在此基础上加入我们需要的功能:加入一个属性value,用来存放RadioButton的key。
代码如下:
public class RadioButton extends android.widget.RadioButton {
private String mValue;
public RadioButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public String getValue() {
return this.mValue;
}
public void setValue(String value) {
this.mValue = value;
}
public RadioButton(Context context, AttributeSet attrs) {
super(context, attrs);
try {
/**
* 跟values/attrs.xml里面定义的属性绑定
*/
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.RadioButton);
this.mValue = a.getString(R.styleable.RadioButton_value);
a.recycle();
} catch (Exception e) {
e.printStackTrace();
}
}
public RadioButton(Context context) {
super(context);
}
}
红色代码可以先不看。先看我们新加入的属性value,由于Android习惯属性命名以m开头。所以我们自定义控件就按照这个规则来写。不过对于setter、getter方法来说,不需要加入m。像上面的:属性名称mValue,setter:setValue(),getter:getValue()。当然,你也可以不按照Android的习惯来命名。
这样,我们就可以使用这个自定义控件了。而且可以给它设置一个value,加上父类的text属性。我们就可以在RadioButton中加入key-value的键值了。当然,这里面的key对应是控件的value属性,value是对应控件的text属性。完了?没有。自定义控件才刚开始了。
2、XML中引用自定义控件
在XML中加入自定义控件其实很简单。只需要在控件名字前加入包名即可。如下:
<org.kandy.view.RadioButton android:id="@id/isPayDepositTrue" fsms:value="true"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/yes" android:textSize="18sp">
</org.kandy.view.RadioButton>
同样,红色部分可以先不看,也不需要加入到代码中,这个时候加入会报错,请注意。(实践不用加)
3、attrs.xml属性定义。
在我们的思想中,既然我在自定义控件中加入了一个新的属性,那么我就应该能够在xml中引用它,并对它赋初始值。我当初也是这样想的。可是却无从下手。就是这一点,折腾了我一个下午。
正解:res/values/attrs.xml中定义属性,在自定义控件中获取这个属性,然后跟自定义控件的属性相绑定。
attrs.xml如果没有,就新建一个。这里只存放自定义控件中需要的属性,在我看来,这个文件是一个中介,负责将layout/xx.xml里面的对这个变量的引用和自定义控件里面的属性绑定起来。
attrs.xml完整代码如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RadioButton"><!-- 控件名称-->
<attr name="value" format="string"/><!-- 属性名称,类型-->
</declare-styleable>
</resources>
如果res下没有错误的话,在R中应该就会生成这些资源的id。这样我们就能在自定义控件中引用他们。
这里我们可能对format不是很熟悉,目前Android系统内置的格式类型有integer比如ProgressBar的进度值,float比如RatingBar的值可能是3.5颗星,boolean比如ToggleButton的是否勾选,string比如TextView的text属性,当然除了我们常见的基础类型外,Android的属性还有特殊的比如color是用于颜色属性的,可以识别为#FF0000等类型,当然还有dimension的尺寸类型,比如23dip,15px,18sp的长度单位,还有一种特殊的为reference,一般用于引用@+id/cwj @drawable/xxx这样的类型。
当然什么时候用reference呢? 我们就以定义一个颜色为例子,
<attr name="red" format="color|reference" /> 这里我们用了逻辑或的运算符,定义的红色是颜色类型的,同时可以被引用。
4、控件属性与XML定义绑定。
这下子我们又回到了自定义控件的编写上来了。先看看我们在第一点提到的红色字体部分。这一部分就是实现控件属性与XML定义绑定的代码。
/**
* 跟values/attrs.xml里面定义的属性绑定
*/
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.RadioButton);
this.mValue = a.getString(R.styleable.RadioButton_value);
a.recycle();
TypedArray其实就是一个存放资源的Array,首先从上下文中获取到R.styleable.RadioButton这个属性资源的资源数组。attrs是构造函数传进来,应该就是对应attrs.xml文件。a.getString(R.styleable.RadioButton_value);这句代码就是获取attrs.xml中定义的属性,并将这个属性的值传给本控件的mValue.最后,返回一个绑定结束的信号给资源:a.recycle();绑定结束。
5、在xml中对控件赋初始值。
请看第2点,绑定结束后可以在需要赋初始值的地方赋值。
<ScrollView android:layout_width="fill_parent"
android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fsms=http://schemas.android.com/apk/res/com.***.***>
<com.***.***.RadioButton android:id="@id/isPayDepositTrue" fsms:value="true"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/yes" android:textSize="18sp">
</com.***.***.RadioButton>
</ScrollView>
红色部分首先声明命名空间。命名空间为fsms.路径是http://schemas.android.com/apk/res/这一部分是不变的,后面接的是R的路径:com.***.***.R。然后在自定义控件的xml描述中就可以这样使用fsms:value="true"。这样就实现了自定义控件的初始化赋值。
6、RadioGroup、RadioButton组合控件的实现
上面是自定义控件的实现,下面将要说的是组合控件的实现。在组合控件中,最经常用到的应该就是RadioGroup和RadioButton。RadioButton的实现已经在上面介绍了。下面要介绍RadioGroup的自定义控件和功能扩展:
代码如下:
public class RadioGroup extends android.widget.RadioGroup {
private String mValue;
public RadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RadioGroup(Context context) {
super(context);
}
// 设置子控件的值
public void setChildValue(){
int n = this.getChildCount();
for(int i=0;i<n;i++){
final RadioButton radio = (RadioButton)this.getChildAt(i);
if(radio.getValue().equals(this.mValue)){
radio.setChecked(true);
}else{
radio.setChecked(false);
}
}
}
// 获取子类的值
public void getChildValue(){
int n = this.getChildCount();
for(int i=0;i<n;i++){
RadioButton radio = (RadioButton)this.getChildAt(i);
if(radio.isChecked()){
this.mValue=radio.getValue();
}
}
}
public void setValue(String value) {
this.mValue = value;
setChildValue();
}
public String getValue(){
getChildValue();
return this.mValue;
}
}
RadioGroup只做两件事:获取子控件(RadioButton)所选择的值;设置子控件要选择的值。
但是这不能怪google,毕竟才刚刚发展起来,Android提供的只是一个最基本的控件实现,而非一个完整、强大的实现。可幸的是,Android提供了自定义控件的实现。有了自定义控件,我们就可以再Android的基础控件上实现我们想要的功能了。经过一天的摸索,我终于实现了我第一个自定义的组合控件——RadioButton组合RadioGroup!
下面我将带领大家进入Android自定义控件的世界。如果觉得我的文章能够帮助大家的话,请大方留下你的一些话语。因为你们的留言是我分享经验的精神源泉!谢谢!
1、设置自定义控件:Android自带的RadioButton只能存放text,这不符合我们的需求,我们需要一个可以同时存放key-value对应的键值。所以我们要编写一个自定义控件能存放key-value。
设计思路:新建一个类叫org.kandy.view.RadioButton,继承自android.wedget.RadioButton,重写父类的所有构造方法。这样我们就实现了一个跟父类一摸一样的控件。在此基础上加入我们需要的功能:加入一个属性value,用来存放RadioButton的key。
代码如下:
public class RadioButton extends android.widget.RadioButton {
private String mValue;
public RadioButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public String getValue() {
return this.mValue;
}
public void setValue(String value) {
this.mValue = value;
}
public RadioButton(Context context, AttributeSet attrs) {
super(context, attrs);
try {
/**
* 跟values/attrs.xml里面定义的属性绑定
*/
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.RadioButton);
this.mValue = a.getString(R.styleable.RadioButton_value);
a.recycle();
} catch (Exception e) {
e.printStackTrace();
}
}
public RadioButton(Context context) {
super(context);
}
}
红色代码可以先不看。先看我们新加入的属性value,由于Android习惯属性命名以m开头。所以我们自定义控件就按照这个规则来写。不过对于setter、getter方法来说,不需要加入m。像上面的:属性名称mValue,setter:setValue(),getter:getValue()。当然,你也可以不按照Android的习惯来命名。
这样,我们就可以使用这个自定义控件了。而且可以给它设置一个value,加上父类的text属性。我们就可以在RadioButton中加入key-value的键值了。当然,这里面的key对应是控件的value属性,value是对应控件的text属性。完了?没有。自定义控件才刚开始了。
2、XML中引用自定义控件
在XML中加入自定义控件其实很简单。只需要在控件名字前加入包名即可。如下:
<org.kandy.view.RadioButton android:id="@id/isPayDepositTrue" fsms:value="true"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/yes" android:textSize="18sp">
</org.kandy.view.RadioButton>
同样,红色部分可以先不看,也不需要加入到代码中,这个时候加入会报错,请注意。(实践不用加)
3、attrs.xml属性定义。
在我们的思想中,既然我在自定义控件中加入了一个新的属性,那么我就应该能够在xml中引用它,并对它赋初始值。我当初也是这样想的。可是却无从下手。就是这一点,折腾了我一个下午。
正解:res/values/attrs.xml中定义属性,在自定义控件中获取这个属性,然后跟自定义控件的属性相绑定。
attrs.xml如果没有,就新建一个。这里只存放自定义控件中需要的属性,在我看来,这个文件是一个中介,负责将layout/xx.xml里面的对这个变量的引用和自定义控件里面的属性绑定起来。
attrs.xml完整代码如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RadioButton"><!-- 控件名称-->
<attr name="value" format="string"/><!-- 属性名称,类型-->
</declare-styleable>
</resources>
如果res下没有错误的话,在R中应该就会生成这些资源的id。这样我们就能在自定义控件中引用他们。
这里我们可能对format不是很熟悉,目前Android系统内置的格式类型有integer比如ProgressBar的进度值,float比如RatingBar的值可能是3.5颗星,boolean比如ToggleButton的是否勾选,string比如TextView的text属性,当然除了我们常见的基础类型外,Android的属性还有特殊的比如color是用于颜色属性的,可以识别为#FF0000等类型,当然还有dimension的尺寸类型,比如23dip,15px,18sp的长度单位,还有一种特殊的为reference,一般用于引用@+id/cwj @drawable/xxx这样的类型。
当然什么时候用reference呢? 我们就以定义一个颜色为例子,
<attr name="red" format="color|reference" /> 这里我们用了逻辑或的运算符,定义的红色是颜色类型的,同时可以被引用。
4、控件属性与XML定义绑定。
这下子我们又回到了自定义控件的编写上来了。先看看我们在第一点提到的红色字体部分。这一部分就是实现控件属性与XML定义绑定的代码。
/**
* 跟values/attrs.xml里面定义的属性绑定
*/
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.RadioButton);
this.mValue = a.getString(R.styleable.RadioButton_value);
a.recycle();
TypedArray其实就是一个存放资源的Array,首先从上下文中获取到R.styleable.RadioButton这个属性资源的资源数组。attrs是构造函数传进来,应该就是对应attrs.xml文件。a.getString(R.styleable.RadioButton_value);这句代码就是获取attrs.xml中定义的属性,并将这个属性的值传给本控件的mValue.最后,返回一个绑定结束的信号给资源:a.recycle();绑定结束。
5、在xml中对控件赋初始值。
请看第2点,绑定结束后可以在需要赋初始值的地方赋值。
<ScrollView android:layout_width="fill_parent"
android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fsms=http://schemas.android.com/apk/res/com.***.***>
<com.***.***.RadioButton android:id="@id/isPayDepositTrue" fsms:value="true"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/yes" android:textSize="18sp">
</com.***.***.RadioButton>
</ScrollView>
红色部分首先声明命名空间。命名空间为fsms.路径是http://schemas.android.com/apk/res/这一部分是不变的,后面接的是R的路径:com.***.***.R。然后在自定义控件的xml描述中就可以这样使用fsms:value="true"。这样就实现了自定义控件的初始化赋值。
6、RadioGroup、RadioButton组合控件的实现
上面是自定义控件的实现,下面将要说的是组合控件的实现。在组合控件中,最经常用到的应该就是RadioGroup和RadioButton。RadioButton的实现已经在上面介绍了。下面要介绍RadioGroup的自定义控件和功能扩展:
代码如下:
public class RadioGroup extends android.widget.RadioGroup {
private String mValue;
public RadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RadioGroup(Context context) {
super(context);
}
// 设置子控件的值
public void setChildValue(){
int n = this.getChildCount();
for(int i=0;i<n;i++){
final RadioButton radio = (RadioButton)this.getChildAt(i);
if(radio.getValue().equals(this.mValue)){
radio.setChecked(true);
}else{
radio.setChecked(false);
}
}
}
// 获取子类的值
public void getChildValue(){
int n = this.getChildCount();
for(int i=0;i<n;i++){
RadioButton radio = (RadioButton)this.getChildAt(i);
if(radio.isChecked()){
this.mValue=radio.getValue();
}
}
}
public void setValue(String value) {
this.mValue = value;
setChildValue();
}
public String getValue(){
getChildValue();
return this.mValue;
}
}
RadioGroup只做两件事:获取子控件(RadioButton)所选择的值;设置子控件要选择的值。
发表评论
-
ActivityGroup 替代tabActivity
2013-12-26 16:43 2544转载自http://www.cnblogs.com/answe ... -
Android实战技巧:为从右向左语言定义复杂字串
2013-09-04 17:37 1146我们所使用的语言,无论是中文还是英语, ... -
Android 5种方式存储数据:
2013-05-08 17:17 1106Android 提供了5种方式存储数据: --使用Shared ... -
widget的设计与应用
2013-02-02 16:27 9331.AppWidgetProviderInfo对象 ... -
Android系统主题设计和实现
2012-12-11 14:09 1498转自:http://www.apkbus.com/ ... -
Android实现DES对字符串加密
2012-09-02 14:15 17165import java.io.Unsuppor ... -
android综合
2012-08-02 16:25 15941 ,手动设置横竖屏 TestA ... -
onSaveInstanceState
2012-08-01 17:40 729@Override //存储 public void onSa ... -
处理多个Activity
2012-07-20 09:40 713public class LifecycleManager ... -
bitmap 和drawable 互相转换
2012-07-19 13:37 653// bitmap to drawable; Drawable ... -
设置壁纸的三种方法
2012-07-19 11:46 25331111111111111111111111111111111 ... -
sqlite数据库处理时间问题 和 日期时间函数
2012-06-27 10:36 22845首先,sqlite数据库在时间 ... -
app缓存管理
2012-06-27 10:25 1059无论大型或小型应用, ... -
Uri、UriMatcher、ContentUris类使用介绍&&Android应用间数据共享之ContentProvider
2012-05-24 15:50 4431Android应用开发中我们会经常用Uri进行数据的处理,下面 ... -
getWidth()为0
2012-04-12 10:06 2016一般在刚开始开发android时,会犯一个错误,即在View的 ... -
搜索手机联系人所有字段
2012-03-28 15:54 1452想取手机联系人的有效字段,但是苦于找不到API表示的字段变量, ... -
Andoid2.X各字段意义
2012-03-28 14:59 1258ContactsContract.Contacts.TIMES ... -
SMS发送流程
2012-03-20 18:07 1262发短信流程: 1 afterTextChanged{mWork ... -
Android telephony MMS 学习笔记
2012-03-14 13:32 2885转载 http://blog.csdn.net/tjy1985 ... -
Android_Mms源代码接受短信流程
2012-03-14 13:27 978短信来了之后framework会发送广播 “android.p ...
相关推荐
在实际项目中,你还可以结合使用自定义ViewGroup来管理多个自定义View,实现更复杂的布局和交互逻辑。例如,自定义的GridView或RecyclerView可以提供更灵活的数据展示方式。 总之,这个“android 自定义view比较...
在Android开发中,自定义View和自定义属性是提升应用个性化和功能扩展性的重要手段。本文将深入探讨这两个核心概念,以及如何在实际项目中应用它们。 ### 自定义View 自定义View允许开发者创建自己的视图组件,以...
5. **属性解析**:如果自定义View需要接受XML属性,可以使用`AttributeSet`来解析属性值。这通常在构造函数中完成,通过调用`obtainStyledAttributes(TypedArray)`方法获取属性数组,然后通过索引读取对应的值。 6....
在自定义LinearLayout中使用GridView,可以将多个自定义View以网格的形式展示出来。GridView是一个可滚动的控件,它可以自动将子视图排列成行和列。为了实现这个功能,我们需要在自定义LinearLayout中添加一个...
总结来说,自定义View使用自定义属性的过程主要包括:在`attrs.xml`中声明属性,通过`TypedArray`获取属性值,并在自定义View的逻辑中应用这些属性。这个过程增强了Android组件的可定制性,使得开发者能够创建出更...
7. **版本兼容性**:考虑到Android系统的碎片化,开发者应确保自定义View能在不同版本的Android系统上正常工作,可能需要使用条件编译或者Support Library。 文件名`tryDynamicLayout`暗示了这是一个关于动态布局的...
Android 的自定义 View 为开发者定义和使用个性化的 View 提供了很好的支持,想要使用自己定义的 View,需要继承 View 类,并重写构造函数和 onDraw() 函数。onDraw 函数在界面刷新时会被调用,通过线程控制可以...
2. **重写构造函数**:我们需要提供至少一个构造函数,以便在布局XML文件中使用自定义View时进行实例化。通常,我们会重写`CompassView(Context context)`和`CompassView(Context context, AttributeSet attrs)`这两...
6. **动画和属性动画**:自定义View还可以集成Android的动画系统,包括使用Animation类实现帧动画,或使用PropertyAnimator实现更灵活的属性动画。 在自定义View的进阶部分,我们可能会关注以下几个高级话题: - *...
7. **自定义View与XML布局**:为了让自定义View易于在XML布局中使用,需要提供对应的构造函数和属性。`attr.xml`文件用于定义自定义属性,`LayoutInflater`用于实例化自定义View。 8. **自定义View的最佳实践**:...
在Android开发中,自定义View是一项重要的技能,它允许开发者根据特定需求创建独特且功能丰富的UI组件。本项目"Android 自定义View实现水平温度计"就是这样一个实例,它通过自定义View来展示一个水平方向的温度计,...
5. **使用自定义View**:最后,在布局XML文件中引用自定义View,并设置相关属性。 ```xml android:layout_width="wrap_content" android:layout_height="wrap_content" /> ``` **二、自定义Button** 自定义...
本文将深入探讨如何实现自定义View的拖动和点击效果,主要通过两种方法进行讲解:一是使用`setOnTouchListener`并重写`onTouch`方法,二是直接在自定义View中实现`onTouchEvent`方法。 ### 方法一:通过`...
它可能包含了自定义View的实例,展示如何使用OpenGL ES进行图形绘制,或者是使用MediaCodec进行视频处理。 综上所述,这个资源包对于想要提升Android自定义View能力的开发者来说,是一份宝贵的资料。通过学习和实践...
自定义View的性能优化主要包括减少无效绘制(使用View的可见性判断、避免过度绘制)、使用硬件加速、合理使用测量模式和复用View等策略。特别地,应当避免在`onDraw()`中执行耗时操作,因为这将直接影响到UI的流畅度...
8. **使用ViewGroup**:如果自定义View需要包含其他子视图,可以继承`android.widget.ViewGroup`,并重写`onLayout()`方法来安排子视图的位置。 9. **使用Drawable**:通过`Drawable`来绘制复杂图形,例如背景、...
1. **动画效果**:自定义View中常使用`ObjectAnimator`、`ValueAnimator`或者`PropertyAnimator`实现平移、旋转、缩放等动画。 2. **手势识别**:通过`GestureDetector`和`ScaleGestureDetector`可以识别滑动、点击...
笔者之前已经写过了一些自定义View的文章...笔者之前的文章中仅仅介绍了如何使用自定义View以及为什么要使用自定义View等等,但是在实际操作中,我们还是希望自定义View之后,直接能够在xml中就对其进行操作,如下图:
在Android开发中,自定义View是一种常见的需求,它允许开发者根据特定需求定制用户界面,提供独特的交互体验。本文将深入探讨“自定义view-画板”这一主题,它是一个用于实现类似“你画我猜”游戏功能的画笔组件。这...
在Android开发中,自定义View是一项常见的任务,它允许开发者根据特定需求创建独特且功能丰富的UI组件。然而,在实现自定义View时,我们可能会遇到一些冲突问题,这可能源于多种原因,如重名、资源ID冲突、布局管理...