自定义组合控件
来源:互联网 发布:java 获取今天星期几 编辑:程序博客网 时间:2024/05/22 12:17
这种自定义组合控件在什么情况下用呢?或者大家在做项目时候会发现,某些布局会被重复的利用,同一个布局的XML代码块会被重复的复制黏贴多次,这样会造成代码结构混乱不说,代码量也会增大,各种控件都需要在Java代码中被申明和处理相应的逻辑,工作量着实不小,所以,必须要找到一个合理的“偷懒”的方式,开动脑经去怎么简化以上说的不必要的麻烦。下面看一张图,就一个简单的布局,我们就此图来实现一个简单的自定义组合控件。
从上面的图来分析,我们可以看到,这个布局里面是没有“全新”的控件的,用的都是Android系统原生的控件。熟悉Android界面布局的人,肯定觉得这种布局真是小Case,太简单了,分分钟就可以写完。于是下面就是某一个条目的布局代码:
<!--?xml version=
1.0
encoding=utf-
8
?-->
<relativelayout android:background=
"@drawable/selector_blue"
android:id=
"@+id/rl_show_address"
android:layout_height=
"60dip"
android:layout_width=
"match_parent"
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<textview android:id=
"@+id/tv_title"
android:layout_height=
"wrap_content"
android:layout_marginleft=
"5dip"
android:layout_margintop=
"1dip"
android:layout_width=
"wrap_content"
android:text=
"这是标题"
android:textcolor=
"#000000"
android:textsize=
"20sp"
>
<textview android:id=
"@+id/tv_desc"
android:layout_below=
"@id/tv_title"
android:layout_height=
"wrap_content"
android:layout_marginleft=
"6dip"
android:layout_margintop=
"1dip"
android:layout_width=
"wrap_content"
android:text=
"这是描述内容"
android:textcolor=
"#99ff0000"
android:textsize=
"14sp"
>
<checkbox android:clickable=
"false"
android:focusable=
"false"
android:id=
"@+id/cb_status"
android:layout_alignparentright=
"true"
android:layout_centervertical=
"true"
android:layout_height=
"wrap_content"
android:layout_width=
"wrap_content"
>
<!-- 加一条分割线 -->
<view android:background=
"#000000/"
android:layout_alignbottom=
"@id/cb_status"
android:layout_alignparentbottom=
"true"
android:layout_height=
"0.2dip"
android:layout_margintop=
"7dip"
android:layout_width=
"match_parent"
>
</view></checkbox></textview></textview></relativelayout>
也许,我们可以相出一个偷懒的方法来呢。通过分析上面的布局,可以发现,布局上每一个子条目是不变的,布局完全一样,唯一在变化的是,红色的TextView上的文本随着CheckBox的状态再改变着,而这种变化,我们是否可以想办法抽取到某个方法中呢,答案是肯定能的。我们可以将这种子条目的布局一次性封装到一个Java类中,每次调用这个控件的时候,事先设定各种属性数据即可,这里涉及到了自定义属性了,关于自定义属性,可以参考我的上一篇博客,Android自定义控件——自定义属性,在这里就不在赘述了。分析一下这个属性集该怎么定义,从上面的图片可以看出,控件上需要设置的内容分别是,上面TextView的标题,还有下面TextView的描述信息,且描述信息是根据CheckBox的状态发生改变的,所以这两种状态(true或false)都需要被定义到属性集里去,于是属性集就有了。
在工程下的res/values目录下,新建attrs.xml文件,定义如下属性集:
<!--?xml version=
1.0
encoding=utf-
8
?-->
<resources>
<declare-styleable name=
"combinationView"
>
<attr name="title" format="string"/>
<attr name="desc_on" format="string"/>
<attr name="desc_off" format="string"/>
</declare-styleable>
</resources>
注意:name="combinationView"的combinationView是自定义控件类的类名
定义好了属性集了,接下来我们就需要定义一个Java类,来渲染这段布局,解析这个属性集,并且对象提供修改控件状态的方法,已达到复用的效果。问题来了,我们定义的这个Java类需要继承哪个类呢?在这里,我们不必考虑View了,因为这里不是全新自定义控件,不需要onMessure和onDraw去测量去画一个视图。那么ViewGroup呢?我们也不必用这个类,因为这里的布局是给定好的,不需要使用onLayout给子控件设置显示的位置。那么,该继承什么呢?我们可以想象一下ViewGroup的子类是不是可以呢?实现自定义控件的除了继承View和ViewGroup之外,还可以直接继承Android已有的控件进行修改,这个用面向对象的思想,应该不难想象吧。由于,该布局文件用的相对布局RelativeLayout,我们想当然可以自定义Java类去继承这个RelativeLayout,RelativeLayout里提供一些参数和方法方便我们去实现子控件的布局。但是,我们这里直接在子控件布局已经写好了,不需要使用RelativeLayout提供的参数和方法来布局了。所以,导致了,即使不去继承RelativeLayout,而改成LinearLayout,FrameLayout...也是可以的,只要这个布局类是ViewGroup的子类就行。以下是这个自定义组合控件的实现代码:
package
com.example.combinationview;
import
android.content.Context;
import
android.util.AttributeSet;
import
android.view.View;
import
android.widget.CheckBox;
import
android.widget.RelativeLayout;
import
android.widget.TextView;
public
class
CombinationView
extends
RelativeLayout {
private
TextView tv_title;
private
TextView tv_desc;
private
CheckBox cb_status;
// 命名空间,在引用这个自定义组件的时候,需要用到
private
String namespace = http:
//schemas.android.com/apk/res/com.example.combinationview;
// 标题
private
String title;
// 被选中的描述
private
String desc_on;
// 未被选中的描述
private
String desc_off;
public
CombinationView(Context context, AttributeSet attrs) {
super
(context, attrs);
// 将自定义组合控件的布局渲染成View
View view = View.inflate(context, R.layout.layout_combinationview,
this
);
tv_title = (TextView) view.findViewById(R.id.tv_title);
tv_desc = (TextView) view.findViewById(R.id.tv_desc);
cb_status = (CheckBox) view.findViewById(R.id.cb_status);
title = attrs.getAttributeValue(namespace, title);
desc_on = attrs.getAttributeValue(namespace, desc_on);
desc_off = attrs.getAttributeValue(namespace, desc_off);
System.out.println(title + : + desc_on + : + desc_off);
// 初始化到子控件
if
(title !=
null
) {
tv_title.setText(title);
}
if
(desc_off !=
null
) {
tv_desc.setText(desc_off);
}
}
/**
* 判断是否被选中
*
* @return
*/
public
boolean
isChecked() {
return
cb_status.isChecked();
}
/**
* 设置选中的状态
*
* @param isChecked
*/
public
void
setChecked(
boolean
isChecked) {
cb_status.setChecked(isChecked);
if
(isChecked) {
tv_desc.setText(desc_on);
}
else
{
tv_desc.setText(desc_off);
}
}
}
下面是引用这个自定义组合控件的方法,首先需要在Activity的布局文件中定义出来:
<linearlayout android:layout_height=
"match_parent"
android:layout_width=
"match_parent"
android:orientation=
"vertical"
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:example=
"http://schemas.android.com/apk/res/com.example.combinationview"
>
<com.example.combinationview.combinationview android:id=
"@+id/cv_first"
android:layout_height=
"wrap_content"
android:layout_width=
"match_parent"
example:desc_off=
"我是未被选中的描述1"
example:desc_on=
"我是被选中的描述1"
example:title=
"我是标题1"
>
</com.example.combinationview.combinationview>
<com.example.combinationview.combinationview android:id=
"@+id/cv_second"
android:layout_height=
"wrap_content"
android:layout_width=
"match_parent"
example:desc_off=
"我是未被选中的描述2"
example:desc_on=
"我是被选中的描述2"
example:title=
"我是标题2"
>
</com.example.combinationview.combinationview>
<com.example.combinationview.combinationview android:id=
"@+id/cv_third"
android:layout_height=
"wrap_content"
android:layout_width=
"match_parent"
example:desc_off=
"我是未被选中的描述3"
example:desc_on=
"我是被选中的描述3"
example:title=
"我是标题3"
>
</com.example.combinationview.combinationview>
<com.example.combinationview.combinationview android:id=
"@+id/cv_fourth"
android:layout_height=
"wrap_content"
android:layout_width=
"match_parent"
example:desc_off=
"我是未被选中的描述4"
example:desc_on=
"我是被选中的描述4"
example:title=
"我是标题4"
>
</com.example.combinationview.combinationview>
</linearlayout>
xmlns:example=http:
//schemas.android.com/apk/res/com.example.combitionview
下面是Activity里面的业务逻辑代码,没什么好说的
package
com.example.combinationview;
import
android.os.Bundle;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.app.Activity;
public
class
MainActivity
extends
Activity
implements
OnClickListener {
private
CombinationView cv_first;
private
CombinationView cv_second;
private
CombinationView cv_third;
private
CombinationView cv_fourth;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cv_first = (CombinationView) findViewById(R.id.cv_first);
cv_second = (CombinationView) findViewById(R.id.cv_second);
cv_third = (CombinationView) findViewById(R.id.cv_third);
cv_fourth = (CombinationView) findViewById(R.id.cv_fourth);
cv_first.setOnClickListener(
this
);
cv_second.setOnClickListener(
this
);
cv_third.setOnClickListener(
this
);
cv_fourth.setOnClickListener(
this
);
}
@Override
public
void
onClick(View v) {
switch
(v.getId()) {
case
R.id.cv_first:
if
(cv_first.isChecked()) {
cv_first.setChecked(
false
);
}
else
{
cv_first.setChecked(
true
);
}
break
;
case
R.id.cv_second:
if
(cv_second.isChecked()) {
cv_second.setChecked(
false
);
}
else
{
cv_second.setChecked(
true
);
}
break
;
case
R.id.cv_third:
if
(cv_third.isChecked()) {
cv_third.setChecked(
false
);
}
else
{
cv_third.setChecked(
true
);
}
break
;
case
R.id.cv_fourth:
if
(cv_fourth.isChecked()) {
cv_fourth.setChecked(
false
);
}
else
{
cv_fourth.setChecked(
true
);
}
break
;
default
:
break
;
}
}
}
好了,关于自定义组合控件就讲完了,非常简单,但是比较常用。以后在项目用到时,想想实现步骤,自定义一种的组合的控件,用起来确实比较方便,比单纯的复制黏贴不仅高大上,而且提高代码的复用性,简化了代码的结构和减少了代码量。
总结步骤:
1、定义自定义控件的布局
2、在res/values下定义attrs.xml文件
3、编写自定义控件类,继承RelativLayout等。实现其构造方法。构造方法中需要完成动态添加布局文件、获取属性值、使用属性值更新控件中内容。
4、在布局文件使用该自定义控件并设置属性值
- 自定义控件-组合控件
- 自定义组合控件,组合模式
- Android自定义组合控件
- android自定义组合控件
- 自定义组合控件
- 1.11 自定义组合控件
- 自定义组合控件
- 自定义组合控件
- 自定义组合控件
- 自定义组合控件.txt
- Android自定义组合控件
- 07自定义组合控件
- 自定义组合控件
- android组合自定义控件
- android 自定义组合控件
- 自定义组合控件
- android 自定义组合控件
- android 自定义组合控件
- 主角受伤处理:屏幕上显示血红效果
- VS2013 全局搜索的结果不显示结果所在文件名和所在行
- sift算法—图像的高斯金字塔的生成(1)
- C++作业7
- (4.2.28)项目中使用的gif开源组件----android-gif-drawable
- 自定义组合控件
- CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙,配置apache
- 学习日志————MySQL练习
- Android 项目中values-v11 values-v14这两个文件夹中的style.xml是干嘛的?
- php学习第二天---基础点5
- JavaScript学习笔记二:字符串
- java成员变量和方法的public等访问限定符的访问权限
- 任意半径局部直方图类算法在PC中快速实现的框架。
- IOS infoplist介绍