当前位置:操作系统 > 安卓/Android >>

Android ApiDemos示例解析(109):Views->Custom

Android 系统提供了很多功能强大的UI组件,包括Button,TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner ,AutoCompleteTestView 等以及LinerLayout, FrameLayout ,RelativeLayout 等布局管理组件可以应用于大部分的应用。

如果执行系统自带的UI控件不能满足应用的需要,Android允许你自定义UI控件,可以有多种方法来构造新的自定义UI控件:

修改或扩展系统自带的UI控件,这些系统定义的UI控件定义其对应的基本UI功能,比如Button 提供了按钮的功能,可以通过重载这些UI控件的事件和onDraw事件来扩充UI功能以及显示。
提供组合多个基本UI控件构造较为复杂的UI直接,比如可以使用TextView和Button(点击后显示一个浮点的ListView)来创建一个Dropdown 组合框控件。
以View 或ViewGroup 为基类构造一个全新的UI控件。
本例采用了第三种方法,创建了一个全新的LabelView:

<com.example.android.apis.view.LabelView
android:background=”@drawable/red”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
app:text=”Red”/>

下面为构造完全自定义UI控件的一般步骤和注意事项,完全自定义UI控件的给开发人员最大的控制能力,可以显示任意的外观或实现系统定义的UI控件无法实现的功能。

以View 为基类派生自定义View组件。
实现使用Context, ArributeSet 为参数的构造函数,这些函数是使用XML描述UI时需调用的。
创建所需要的自定义的事件Listener,属性等这一步不是必须的,可以根据UI组件功能自行决定。
重载onMeasure 和onDraw ,缺省的onMeasure 将UI控件的大小定义为100X100大小,如果这个大小恰巧正是你需要的,你可以使用缺省的onMeasure,
根据需要重载其它所需的on…方法。
这个自定义LabelView可以用来显示一行文字,定义了三个属性:

text: 文字内容
textSize:文字大小
textColor:文字颜色
这些属性在layout 中使用 app:text=”Red”,app:textSize=”20dp”,app:textColor=”#ffffffff”

来看看LabelView 的具体实现:

首先以View为基类,并定义了LabelView的几个属性,用来保存文字的大小,内容和颜色,mText为文字内容,其它两个保存了颜色和大小。

[java] 
public class LabelView extends View { 
 private Paint mTextPaint; 
 private String mText; 
 private int mAscent; 

public class LabelView extends View {
 private Paint mTextPaint;
 private String mText;
 private int mAscent;

然后实现构造函数

[java] 
public LabelView(Context context) { 
 super(context); 
 initLabelView(); 

 
public LabelView(Context context, AttributeSet attrs) { 
 super(context, attrs); 
 initLabelView(); 
 ... 

public LabelView(Context context) {
 super(context);
 initLabelView();
}

public LabelView(Context context, AttributeSet attrs) {
 super(context, attrs);
 initLabelView();
 ...
}

其中public LabelView(Context context, AttributeSet attrs) 是使用Layout定义LabelView必须实现的。而且一般需要调用基类的对应方法。如果不定义该构造函数,此时如果在Layout定义LabelView,Android展开Layout资源文件时找不到所需构造函数,应用将抛出异常退出。

因为LabelView定义了三个自定义属性Text, TextSize,TextColor ,并可以用在Layout定义中,在构造函数中可以获取这些属性值。

自定义属性的步骤如下:

1. 在 values\attrs.xml 中定义属性 ,如LabelView定义的属性如下:

<declare-styleable name=”LabelView”>
<attr name=”text” format=”string” />
<attr name=”textColor” format=”color” />
<attr name=”textSize” format=”dimension” />
< /declare-styleable>

如果使用系统支持的属性如android:text 则不需要定义format 属性。这个attrs 对应的ID为 R.styleable.LableView (自动生成在R.java 中)

2. 使用Context 的 obtainStyledAttributes 获取属性值

[java] 
 TypedArray a = context.obtainStyledAttributes(attrs, 
 R.styleable.LabelView); 
 
CharSequence s 
 = a.getString(R.styleable.LabelView_text); 
 
setTextColor(a.getColor(R.styleable.LabelView_textColor, 
 0xFF000000)); 
 
int textSize 
 = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0); 

 TypedArray a = context.obtainStyledAttributes(attrs,
 R.styleable.LabelView);

CharSequence s
 = a.getString(R.styleable.LabelView_text);

setTextColor(a.getColor(R.styleable.LabelView_textColor,
 0xFF000000));

int textSize
 = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0);
obtainStyledAttributes 返回的类型为TypedArray ,然后就可以使用TypedArray的getXXX方法来取得所需的属性值,第一个参数为属性的ID,第二个参数为找不到对应属性时缺省值。

3.在Layout XML 文件中添加 属性对应的namespace 定义,如

xmlns:app=”http://schemas.android.com/apk/res/com.example.android.apis

然后就可以使用app:xxx 来引用自定义控件的属性了,如:

<com.example.android.apis.view.LabelView
android:background=”@drawable/blue”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
app:text=”Blue” app:textSize=”20dp”/>

4.属性property对应的代码为 getProperty, setProperty

如text 的设置方法:

[java]
public void setText(String text) { 
 mText = text; 
 requestLayout(); 
 invalidate(); 

public void setText(String text) {
 mText = text;
 requestLayout();
 invalidate();
}
然后一个重要的方法是onMeausre ,在这个方法在必须调用setMeasureDimension 方法来告诉本View的Container类(各种Layout类型)所需占据的大小,如果没有设置setMeasureDimension ,Layout将会抛出异常。

[java] 
 protected void onMeasure(int widthMeasureSpec, 
 int heightMeasureSpec) { 
 setMeasuredDimension(measureWidth(widthMeasureSpec), 
 measureHeight(heightMeasureSpec)); 

 protected void onMeasure(int widthMeasureSpec,
 int heightMeasureSpec) {
 setMeasuredDimension(measureWidth(widthMeasureSpec),
 measureHeight(heightMeasureSpec));
}
onMeasure方法来父Layout类为其子类布局时调用,它为某个子类“你需要多大的空间”,传入两个参数:widthMeasureSpec 和heighMeasureSpec ,它们给出了这个UI控件可以使用的空间大小规格参数。 本例使用的measureWidth和measureHeight 代码基本上可以重用到所有的自定义控件中。

最后一步是重载onDraw方法,在屏幕上显示控件的内容:

[java] 
protected void onDraw(Canvas canvas) { 
 super.onDraw(canvas); 
 canvas.drawText(mText, getPaddingLeft(), 
 getPaddingTop() - mAscent, mTextPaint); 

protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 canvas.drawText(mText, getPaddingLeft(),
 getPaddingTop() - mAscent, mTextPaint);
}
onDraw 传入的参数类型为Canvas ,可以使用Canvas绘制任意图形,可以参见ApiDemos 中Graphics 例子。本例根据文本的颜色,大小绘制文本。www.zzzyk.com

如果需要使用3D (OpenGL ES )图形,就不能从View 派生,而应使用SurfaceView 作为基类。

 

\
作者:mapdigit

 


补充:移动开发 , Android ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,