android在两个基本布局类View和ViewGroup的基础上提供了成熟而又强大的构建UI组件模型。首先,平台包含了各种预先构建的View和ViewGroup,他们被称为widget和布局。你可以用他们构建你的UI。
一些可用的widget包括Button,TextView,EditText,ListView,CheckBox,RadioButton,Gallery,Spiner,和更多特殊用户的AutoComploteTextView,ImageSwitcher,TextSwitcher.
一些可以使用的布局如LinearLayout,FramwLayout,RelativeLayout等。
如果已有的widgets和布局不能满足你的要求,你可以创建你自己的View子类。如果你仅仅需要对一些已存在的widget所一些小小的调整,你可以创建他们的子类来重写一些方法。
创建你自己的View的子类可以精确地控制界面元素的外观和功能。对于自定义的View组件,通常有下面几种处理方式:
1.你可以创建一个完全自定义渲染的view类型,例如‘音量控制’旋钮使用2D图形,它类似于一个模拟电子控制。
2.你可以组合一组view组件来构成一个新的、单一的组件。也许类似一个ComboBox(弹出列表和自由文本字段的组合),双窗口的控制选择器(),以此类推。
3.你可以采用一种方式,类似覆盖EditText组件展示在屏幕上(记事本教程使用它效果不错,创建了一个具有线条的页面)。
4.你可以捕获其他的像按键事件和按照自定义的方式处理他们(事件)。
下面就说说如何创建自定义视图和应用程序中使用它们。一些常用的基本做法:
1.扩展已有View的class或者View的子类。
2.覆盖重写父类的一些方法,这些方法通常是以‘on'开头的方法。比如:onDraw,onMeasure(),onKeyDown,等。
3.使用你的新的扩展类。一旦完成,你的新的扩展类可以使用在代替你扩展类的基类的地方。
提示:扩展类通常作为使用它们的活动内的内部类,这样父类可以方方便的控制他。为了扩展它的使用范围,你同样可以设置它为public.
完全自定义组件:
完全自定义组件可以创建你想要的任何图形组件。你可以根据你的想象(组件屏幕尺寸,组件的处理能力)创建你任何喜欢的(组件的)外观和行为。
创建一个完全自定义的组件步骤:
a.继承View类;b.你可以提供一个构造方法,这个构造方法可以从XML文件获得组件的属性和参数。你可以定义你组件的属性和参数;c.你可以为你的组件创建自己的事件监听器,属性访问与修改,甚至更富在的组件行为;d.下面这个就比较重要了。你可以覆盖重写onMeasure(),onDraw()。默认情况下:onDraw()什么也不做,onMeasure()会设置一个100*100的尺寸。e.你或许需要覆盖重写View其他的方法或者定义你自己的方法。
掌握完全自定义组件最重要的两点:首先你了解组件被显示出来的所走的流程,也就是View类哪些方法被调用。其次就是属性与参数的定义。下图我自认为很重要,要好好理解:
上面方法重要的两个:onDraw,onMeasure。那就好好说说他们吧。onDraw()方法传递了一个Canvas对象,这个对象你可以实现任何你想要的:2D图形,其他标准或者自定义的组件,文本风格,或者你其它你想要的(注意:这个并不适应3D图形。如果那样,你必须继承SurfaceView,在一个独立的线程绘画,参考GLSurfaceViewActivity sample).
onMeasure就复杂了,简单的说就是决定你组件size的地方。这个决定的size不光可以是你组件本身size,还包括孩子组件的size(这个是很多人忽略的问题)。它有两个参数,这个两个参数是跟你的组件的layout_width与layout_height有关系。在你计算出你的组件size之后,你就可以使用setMeasuredDimension()就ok了。为什么呢,其实view的调用程序也就是:measure->onMeasure->setMeasuredDimension.
下面就说说一些简单的例子吧:
首先第一个就是samples里面的例子,因为是官方的,这个 必须说说,源代码如下:
/**
* Example of how to write a custom subclass of View. LabelView
* is used to draw simple text views. Note that it does not handle
* styled text or right-to-left writing systems.
*
*/
public class LabelView extends View {
private Paint mTextPaint;
private String mText;
private int mAscent;
/**
* Constructor. This version is only needed if you will be instantiating
* the object manually (not from a layout XML file).
* @param context
*/
public LabelView(Context context) {
super(context);
initLabelView();
}
/**
* Construct object, initializing with any attributes we understand from a
* layout file. These attributes are defined in
* SDK/assets/res/any/classes.xml.
*
* @see android.view.View#View(android.content.Context, android.util.AttributeSet)
*/
public LabelView(Context context, AttributeSet attrs) {
super(context, attrs);
initLabelView();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.LabelView);
CharSequence s = a.getString(R.styleable.LabelView_text);
if (s != null) {
setText(s.toString());
}
// Retrieve the color(s) to be used for this view and apply them.
// Note, if you only care about supporting a single color, that you
// can instead call a.getColor() and pass that to setTextColor().
setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xFF000000));
int textSize = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0);
if (textSize > 0) {
setTextSize(textSize);
}
a.recycle();
}
private final void initLabelView() {
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(16);
mTextPaint.setColor(0xFF000000);
setPadding(3, 3, 3, 3);
}
/**
* Sets the text to display in this label
* @param text The text to display. This will be drawn as one line.
*/
public void setText(String text) {
mText = text;
requestLayout();
invalidate();
}
/**
* Sets the text size for this label
* @param size Font size
*/
public void setTextSize(int size) {
mTextPaint.setTextSize(size);
requestLayout();
invalidate();
}
/**
* Sets the text color for this label.
* @param color ARGB value for the text
*/
public void setTextColor(int color) {
mTextPaint.setColor(color);
invalidate();
}
/**
* @see android.view.View#measure(int, int)
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),
measureHeight(heightMeasureSpec));
}
/**
* Determines the width of this view
* @param measureSpec A measureSpec packed into an int
* @return The width of the view, honoring constraints from measureSpec
*/
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
+ getPaddingRight();
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by measureSpec
result = Math.min(result, specSize);
}
}
return result;
}
/**
* Determines the height of this view
* @param measureSpec A measureSpec packed into an int
* @return The height of the view, honoring constraints from measureSpec
*/
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
mAscent = (int) mTextPaint.ascent();
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop()
+ getPaddingBottom();
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by measureSpec
result = Math.min(result, specSize);
}
}
return result;
}
/**
* Render the text
*
* @see android.view.View#onDraw(android.graphics.Canvas)
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint);
}
}
17 <resources>
18 <!-- These are the attributes that we want to retrieve from the theme
19 in app/PreferencesFromCode.java -->
30 <declare-styleable name="LabelView">
31 <attr name="text" format="string" />
32 <attr name="textColor" format="color" />
33 <attr name="textSize" format="dimension" />
34 </declare-styleable>
35 </resources>
这里它自定义了一个View组建LabelView.它只有三个属性:text,textColor,textSize,及相关方法。在第二个构造函数里,获取xml属性值做一些处理。然后就是onMeasure,onDraw,这个两个没有什么好说的,上面讲了的。