目标:实现textview和ImageButton组合,可以通过Xml设置自定义控件的属性。
1.控件布局:以Linearlayout为根布局,一个TextView,一个ImageButton。
2.自定义控件代码,从LinearLayout继承:
在构造函数中将Xml中定义的布局解析出来。
3.在主界面布局xml中使用自定义控件:
即使用完整的自定义控件类路径:com.demo.widget2.ImageBtnWithText定义一个元素。
运行可以看到控件已经能够被加载到界面上。
4.给按钮设置图片和文本
如果图片是固定不变的,那么直接在控件布局中设置ImageButton的src属性即可。
4.1通过Java代码设置,在控件代码中提供函数接口:
然后再在主界面的onCreate()通过函数调用设置即可。
4.2通过Xml设置属性
4.2.1首先定义Xml可以设置的属性集合,在values下创建attrs.xml,文件名可随意,一般都叫attrs.xml
属性集合名字:ImageBtnWithText,自己可根据实际来定义;
集合中包含的属性列表,每行一个属性。
4.2.2修改自定义控件实现代码,以获取xml中定义的属性
首先通过context.obtainStyledAttributes获得所有属性数组;
然后通过TypedArray类的getXXXX()系列接口获得相应的值。
4.2.3在主界面布局中设置自定义控件的属
android:text="ABC" android:src="@drawable/icon
4.3自定义名称属性:
在4.2中使用的属性名是Android系统命名空间的,都以android开头,比如android:text等。
实际开发中会自定义一些属性名,这些属性名仍然定义在4.2.1提到的attrs.xml中:
4.3.1定义属性名
和直接使用系统的attr不同的是要增加一个format属性,说明此属性是什么格式的。format可选项可参见注1
4.3.2使用自定义属性
直接在主布局文件中使用此属性appendText="abc"是不会设置生效的,而是要在主布局xml中定义一个xml命名空间:
xmlns:myspace="http://schemas.android.com/apk/res/com.demo.customwidget"
命名空间的名字可以自己随便定义,此处为myspace,即xmlns:myspace;
后面的地址则有限制,其开始必须为:"http://schemas.android.com/apk/res/",后面则是包名com.demo.customwidget,
此处的包名与AndroidManifest.xml中< manifest>节点的属性package="com.demo.customwidget"一致,不是自定义控件Java代码所在的包,当然简单的程序自定义控件Java代码也一般在此包内。
注1:format可选项
"reference" //引用
"color" //颜色
"boolean" //布尔值
"dimension" //尺寸值
"float" //浮点值
"integer" //整型值
"string" //字符串
"fraction" //百分数,比如200%
枚举值,格式如下:
< attr name="orientation">
< enum name="horizontal" value="0" />
< enum name="vertical" value="1" />
< /attr>
xml中使用时:
android:orientation = "vertical"
标志位,位或运算,格式如下:
< attr name="windowSoftInputMode">
< flag name = "stateUnspecified" value = "0" />
< flag name = "stateUnchanged" value = "1" />
< flag name = "stateHidden" value = "2" />
< flag name = "stateAlwaysHidden" value = "3" />
< flag name = "stateVisible" value = "4" />
< flag name = "stateAlwaysVisible" value = "5" />
< flag name = "adjustUnspecified" value = "0x00" />
< flag name = "adjustResize" value = "0x10" />
< flag name = "adjustPan" value = "0x20" />
< flag name = "adjustNothing" value = "0x30" />
< /attr>
xml中使用时:
android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden">
另外属性定义时可以指定多种类型值,比如:
< attr name = "background" format = "reference|color" />
xml中使用时:
android:background = "@drawable/图片ID|#00FF00"
最后来个完整实例:
attrs.xml:
meter.xml文件:
使用:
main.xml:
1.控件布局:以Linearlayout为根布局,一个TextView,一个ImageButton。
1
<
?xml
version
="1.0"
encoding
="utf-8"
?
>
2 < LinearLayout xmlns:Android ="http://schemas.android.com/apk/res/android"
3 android:layout_width ="fill_parent" android:layout_height ="fill_parent"
4 android:gravity ="center_vertical" >
5 < TextView android:layout_height ="wrap_content" android:id ="@+id/text1"
6 android:layout_width ="wrap_content" >< /TextView >
7 < ImageButton android:layout_width ="wrap_content"
8 android:layout_height ="wrap_content" android:id ="@+id/btn1" >< /ImageButton >
9 < /LinearLayout >
2 < LinearLayout xmlns:Android ="http://schemas.android.com/apk/res/android"
3 android:layout_width ="fill_parent" android:layout_height ="fill_parent"
4 android:gravity ="center_vertical" >
5 < TextView android:layout_height ="wrap_content" android:id ="@+id/text1"
6 android:layout_width ="wrap_content" >< /TextView >
7 < ImageButton android:layout_width ="wrap_content"
8 android:layout_height ="wrap_content" android:id ="@+id/btn1" >< /ImageButton >
9 < /LinearLayout >
2.自定义控件代码,从LinearLayout继承:
public
class ImageBtnWithText
extends LinearLayout {
}
public ImageBtnWithText(Context context) {
this(context, null);
}
public ImageBtnWithText(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.imagebtn_with_text, this, true);
}
}
}
public ImageBtnWithText(Context context) {
this(context, null);
}
public ImageBtnWithText(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.imagebtn_with_text, this, true);
}
}
在构造函数中将Xml中定义的布局解析出来。
3.在主界面布局xml中使用自定义控件:
<
com.demo.widget2.ImageBtnWithText
android:id ="@+id/widget"
android:layout_width ="fill_parent"
android:layout_height ="fill_parent" />
android:id ="@+id/widget"
android:layout_width ="fill_parent"
android:layout_height ="fill_parent" />
即使用完整的自定义控件类路径:com.demo.widget2.ImageBtnWithText定义一个元素。
运行可以看到控件已经能够被加载到界面上。
4.给按钮设置图片和文本
如果图片是固定不变的,那么直接在控件布局中设置ImageButton的src属性即可。
4.1通过Java代码设置,在控件代码中提供函数接口:
public
void setButtonImageResource(
int resId) {
mBtn.setImageResource(resId);
}
public void setTextViewText(String text) {
mTv.setText(text);
}
mBtn.setImageResource(resId);
}
public void setTextViewText(String text) {
mTv.setText(text);
}
然后再在主界面的onCreate()通过函数调用设置即可。
4.2通过Xml设置属性
4.2.1首先定义Xml可以设置的属性集合,在values下创建attrs.xml,文件名可随意,一般都叫attrs.xml
<
?xml
version
="1.0"
encoding
="utf-8"
?
>
< resources >
< declare-styleable name ="ImageBtnWithText" >
< attr name ="android:text" />
< attr name ="android:src" />
< /declare-styleable >
< /resources >
< resources >
< declare-styleable name ="ImageBtnWithText" >
< attr name ="android:text" />
< attr name ="android:src" />
< /declare-styleable >
< /resources >
属性集合名字:ImageBtnWithText,自己可根据实际来定义;
集合中包含的属性列表,每行一个属性。
4.2.2修改自定义控件实现代码,以获取xml中定义的属性
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ImageBtnWithText);
CharSequence text = a.getText(R.styleable.ImageBtnWithText_android_text);
if(text != null) mTv.setText(text);
Drawable drawable = a.getDrawable(R.styleable.ImageBtnWithText_android_src);
if(drawable != null) mBtn.setImageDrawable(drawable);
a.recycle();
CharSequence text = a.getText(R.styleable.ImageBtnWithText_android_text);
if(text != null) mTv.setText(text);
Drawable drawable = a.getDrawable(R.styleable.ImageBtnWithText_android_src);
if(drawable != null) mBtn.setImageDrawable(drawable);
a.recycle();
首先通过context.obtainStyledAttributes获得所有属性数组;
然后通过TypedArray类的getXXXX()系列接口获得相应的值。
4.2.3在主界面布局中设置自定义控件的属
android:text="ABC" android:src="@drawable/icon
4.3自定义名称属性:
在4.2中使用的属性名是Android系统命名空间的,都以android开头,比如android:text等。
实际开发中会自定义一些属性名,这些属性名仍然定义在4.2.1提到的attrs.xml中:
4.3.1定义属性名
和直接使用系统的attr不同的是要增加一个format属性,说明此属性是什么格式的。format可选项可参见注1
4.3.2使用自定义属性
<
?xml
version
="1.0"
encoding
="utf-8"
?
>
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:myspace ="http://schemas.android.com/apk/res/com.demo.customwidget"
android:orientation ="vertical" android:layout_width ="fill_parent"
android:layout_height ="fill_parent" >
< com.demo.widget2.ImageBtnWithText
android:text ="ABC" android:src ="@drawable/icon" android:id ="@+id/widget"
android:layout_width ="fill_parent" android:layout_gravity ="center"
android:layout_height ="fill_parent" myspace:appendText ="123456" >
< /com.demo.widget2.ImageBtnWithText >
< /LinearLayout >
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:myspace ="http://schemas.android.com/apk/res/com.demo.customwidget"
android:orientation ="vertical" android:layout_width ="fill_parent"
android:layout_height ="fill_parent" >
< com.demo.widget2.ImageBtnWithText
android:text ="ABC" android:src ="@drawable/icon" android:id ="@+id/widget"
android:layout_width ="fill_parent" android:layout_gravity ="center"
android:layout_height ="fill_parent" myspace:appendText ="123456" >
< /com.demo.widget2.ImageBtnWithText >
< /LinearLayout >
直接在主布局文件中使用此属性appendText="abc"是不会设置生效的,而是要在主布局xml中定义一个xml命名空间:
xmlns:myspace="http://schemas.android.com/apk/res/com.demo.customwidget"
命名空间的名字可以自己随便定义,此处为myspace,即xmlns:myspace;
后面的地址则有限制,其开始必须为:"http://schemas.android.com/apk/res/",后面则是包名com.demo.customwidget,
此处的包名与AndroidManifest.xml中< manifest>节点的属性package="com.demo.customwidget"一致,不是自定义控件Java代码所在的包,当然简单的程序自定义控件Java代码也一般在此包内。
注1:format可选项
"reference" //引用
"color" //颜色
"boolean" //布尔值
"dimension" //尺寸值
"float" //浮点值
"integer" //整型值
"string" //字符串
"fraction" //百分数,比如200%
枚举值,格式如下:
< attr name="orientation">
< enum name="horizontal" value="0" />
< enum name="vertical" value="1" />
< /attr>
xml中使用时:
android:orientation = "vertical"
标志位,位或运算,格式如下:
< attr name="windowSoftInputMode">
< flag name = "stateUnspecified" value = "0" />
< flag name = "stateUnchanged" value = "1" />
< flag name = "stateHidden" value = "2" />
< flag name = "stateAlwaysHidden" value = "3" />
< flag name = "stateVisible" value = "4" />
< flag name = "stateAlwaysVisible" value = "5" />
< flag name = "adjustUnspecified" value = "0x00" />
< flag name = "adjustResize" value = "0x10" />
< flag name = "adjustPan" value = "0x20" />
< flag name = "adjustNothing" value = "0x30" />
< /attr>
xml中使用时:
android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden">
另外属性定义时可以指定多种类型值,比如:
< attr name = "background" format = "reference|color" />
xml中使用时:
android:background = "@drawable/图片ID|#00FF00"
最后来个完整实例:
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
public class Meter extends LinearLayout {
private int max=100;
private int incrAmount=1;
private int decrAmount=-1;
private ProgressBar bar= null;
public Meter( final Context ctxt, AttributeSet attrs) {
super(ctxt, attrs);
this.setOrientation(HORIZONTAL);
TypedArray a=ctxt.obtainStyledAttributes(attrs,R.styleable.Meter);
// 获取里面属性用 "名字_ 属性" 连接起来
max=a.getInt(R.styleable.Meter_max, 100);
incrAmount=a.getInt(R.styleable.Meter_incr, 1);
decrAmount=-1*a.getInt(R.styleable.Meter_decr, 1);
a.recycle();
}
// 当View中所有的子控件 均被映射成xml后触发
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// ((Activity)getContext()).getLayoutInflater().inflate(R.layout.meter, this);
LayoutInflater.from(getContext()).inflate(R.layout.meter, this);
bar=(ProgressBar)findViewById(R.id.bar);
bar.setMax(max);
ImageButton btn=(ImageButton)findViewById(R.id.incr);
btn.setOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
bar.incrementProgressBy(incrAmount);
}
});
btn=(ImageButton)findViewById(R.id.decr);
btn.setOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
bar.incrementProgressBy(decrAmount);
}
});
// this.addView(view); // 不需要add,默认已经add了
}
}
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
public class Meter extends LinearLayout {
private int max=100;
private int incrAmount=1;
private int decrAmount=-1;
private ProgressBar bar= null;
public Meter( final Context ctxt, AttributeSet attrs) {
super(ctxt, attrs);
this.setOrientation(HORIZONTAL);
TypedArray a=ctxt.obtainStyledAttributes(attrs,R.styleable.Meter);
// 获取里面属性用 "名字_ 属性" 连接起来
max=a.getInt(R.styleable.Meter_max, 100);
incrAmount=a.getInt(R.styleable.Meter_incr, 1);
decrAmount=-1*a.getInt(R.styleable.Meter_decr, 1);
a.recycle();
}
// 当View中所有的子控件 均被映射成xml后触发
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// ((Activity)getContext()).getLayoutInflater().inflate(R.layout.meter, this);
LayoutInflater.from(getContext()).inflate(R.layout.meter, this);
bar=(ProgressBar)findViewById(R.id.bar);
bar.setMax(max);
ImageButton btn=(ImageButton)findViewById(R.id.incr);
btn.setOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
bar.incrementProgressBy(incrAmount);
}
});
btn=(ImageButton)findViewById(R.id.decr);
btn.setOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
bar.incrementProgressBy(decrAmount);
}
});
// this.addView(view); // 不需要add,默认已经add了
}
}
attrs.xml:
<?
xml version="1.0" encoding="utf-8"
?>
< resources >
< declare-styleable name ="Meter" >
< attr name ="max" format ="integer" />
< attr name ="incr" format ="integer" />
< attr name ="decr" format ="integer" />
</ declare-styleable >
</ resources >
< resources >
< declare-styleable name ="Meter" >
< attr name ="max" format ="integer" />
< attr name ="incr" format ="integer" />
< attr name ="decr" format ="integer" />
</ declare-styleable >
</ resources >
meter.xml文件:
<?
xml version="1.0" encoding="utf-8"
?>
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
android:orientation ="horizontal"
android:layout_width ="fill_parent"
android:layout_height ="wrap_content"
>
< ImageButton android:id ="@+id/decr"
android:layout_height ="wrap_content"
android:layout_width ="wrap_content"
android:scaleType ="fitCenter"
android:src ="@drawable/arrow_down"
/>
< ProgressBar android:id ="@+id/bar"
style ="?android:attr/progressBarStyleHorizontal"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:layout_weight ="1"
android:layout_gravity ="center_vertical"
/>
< ImageButton android:id ="@+id/incr"
android:layout_height ="wrap_content"
android:layout_width ="wrap_content"
android:scaleType ="fitCenter"
android:src ="@drawable/arrow_up"
/>
</ LinearLayout >
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
android:orientation ="horizontal"
android:layout_width ="fill_parent"
android:layout_height ="wrap_content"
>
< ImageButton android:id ="@+id/decr"
android:layout_height ="wrap_content"
android:layout_width ="wrap_content"
android:scaleType ="fitCenter"
android:src ="@drawable/arrow_down"
/>
< ProgressBar android:id ="@+id/bar"
style ="?android:attr/progressBarStyleHorizontal"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:layout_weight ="1"
android:layout_gravity ="center_vertical"
/>
< ImageButton android:id ="@+id/incr"
android:layout_height ="wrap_content"
android:layout_width ="wrap_content"
android:scaleType ="fitCenter"
android:src ="@drawable/arrow_up"
/>
</ LinearLayout >
使用:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
main.xml:
<?
xml version="1.0" encoding="utf-8"
?>
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:app ="http://schemas.android.com/apk/res/com.ql.app"
android:orientation ="horizontal"
android:layout_width ="fill_parent"
android:layout_height ="wrap_content"
>
< com.ql.app.Meter
android:id ="@+id/meter"
android:layout_width ="fill_parent"
android:layout_height ="wrap_content"
app:max ="100"
app:incr ="5"
app:decr ="5"
/>
</ LinearLayout >
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:app ="http://schemas.android.com/apk/res/com.ql.app"
android:orientation ="horizontal"
android:layout_width ="fill_parent"
android:layout_height ="wrap_content"
>
< com.ql.app.Meter
android:id ="@+id/meter"
android:layout_width ="fill_parent"
android:layout_height ="wrap_content"
app:max ="100"
app:incr ="5"
app:decr ="5"
/>
</ LinearLayout >
Trackback:http://gundumw100.iteye.com/blog/1040917