android中-自定义View对象| 我们知道android SDK中的UI控件都是View或ViewGroup的子类(ViewGroup也是View的子类),我们将View细分为单独View和容器View 两种,所以就衍生两个视图基类:View和ViewGroup。通过扩展这两个基类,Android SDK提供了一系列功能强大,设计巧妙的UI控件,但是用户的需求是千变万化的,SDK中不可能提供所有可能用到的UI形式,所以这就需要允许用户自定义 View对象来完成他们所需要的效果。 幸好,Android SDK有支持自定义View对象,它允许你自定义一个类,继承android.view.View对象,然后你只需要调整它里面的一些方法即可,那到底要 重写哪些方法呢?如果你对android.view.View本身都不是很熟悉的话,那怎么会自定义view呢,就像是还不会走路,怎么就想学跑步了,所 以我们首先要先了解一些关于View的东西。 了解android.view.View我们在了解Activity时就有提到,只要有能看到的UI界面,就一定有Activity。这边所说的UI界面就是指View对象,所以View 和Activity离不开关系。当Activity处于Active状态时(Activity获取了当前的焦点),它就发出请求要求绘制Activity 中的View对象。系统根据视图的关系层次从根节点出发开始绘制直到所有的叶子节点(因为View是有层次关系的), 整个绘制过程中View和ViewGroup的实现形式是不一样的,因为ViewGroup里面会有子视图对象,所以它需要请求子视图执行绘制,整个视图 树执行绘图的顺序是中序遍历,从根节点先画,最后才是子节点。如果是View那么只要确定了它的大小即可执行绘制方法。 绘制ViewGroup时可以分为两个步骤:measure测量过程和layout布局过程。measure是用来测量ViewGroup所占用的 尺寸,它按照中序遍历的方式递归调用子视图的measure方法,然后保存各个子视图对应测量出来的结果。当measure测量完成后就会调用 layout过程,layout过程也是使用中序遍历递归调用,它做的工作是确定每个父视图的尺寸,因为在measure阶段已经完成了所有的子视图尺 寸,所以父视图的尺寸也可以通过它计算出来。 当measure测量执行完成后,你就已经知道每个视图所需的尺寸了,所以你需要设置值,让getMeasureWidth和 getMeasureHeight方法可以获取测量得到的结果。measure测量的结果必须考虑父视图设置的长度,确保测量完成后得到的结果满足:所有 的父视图的尺寸都能装得下它们各自的所有子视图。一个父视图可能会多次调用它的子视图的measure方法,因为视图可以设置成最大尺寸 (fill_parent),它首先会不限制子视图的大小,让子视图能尽量大,但是如果有两个子视图都采用最大尺寸(fill_parent),那么只能 采取折中方式。 measure测量过程用两个类来协助确定尺寸:MeasureSpec和LayoutParams。MeasureSpec用来对父视图描述它需要的尺寸或位置,LayoutParams用来描述它需要的宽度和高度,它可定义的尺寸分为3种模型:
MeasureSpec用来让父视图通知子视图,子视图所能分配的大小,它分为下面3种模型:
创建自定义View对象 了解了View测量和绘制的原理后,你就可以通过继承它,重写特定的方法创建一个自定义View对象。一般创建自定义View的用途是: 1. 自定义视图对象,创建一个SDK没提供的布局形式,如Accordion。 2. 将多个View对象组合起来封装成一个新的自定义View对象,如Combox就是由一个下拉列表和一个输入框和输入框右边一个按钮组成的。 3. 改写EditText对象,Android SDK中的记事本例子就使用了扩展EditText的视图,它在每行文字的下面画一条蓝色的线。 4. 创建一个游戏面板,捕捉一些键盘或触摸事件做出一些特定的处理。 如何创建自定义View对象 主要有下面几个步骤: 1. 创建一个自定义类,继承android.view.View。 2. 重写父类构造方法,你可以在构造方法中获取在xml布局文件里设置的属性,你可以从这里读取一些自定义的属性配置View对象。 3. 重写父类(View)的方法,这边可以根据需要修改的程度有选择的重写,这些重写的方法都是on开头的方法如:onDraw、onMeasure或 onKeyDown(这些跟Activity生命周期中的onCreate,onPause…一样也算绘制过程的生命周期)。如果你没有重写onDraw 默认它不做任何事,所以你会看到一片空白区域,onMeasure默认会创建一个100 * 100的区域 4. 使用这个对象 一般我们如果没有在xml布局文件中使用一些自定义的配置属性可以不用重写构造方法,这时候我们只需要重写onMeasure和onDraw方法。 onMeasure方法被调用时有两个参数:widthMeasureSpec和heightMeasureSpec这个参数是int型,用来表示宽度和 高度的尺寸,在onMeasure中必须根据这两个参数确定View的宽度和高度值,然后调用setMeasureDimension(int width,int height)方法设置视图的显示区域范围,否则将会抛出异常。在onDraw方法中,会有一个调用参数:Canvas,你可以使用它进行绘制View的 操作。 下面我们使用一个简单的例子演示下如何自定义一个View对象,我们先讲述下这个例子实现的效果:例子将展现一个蓝色背景的面板,当你点击面板中的 某点时会以这个点击点为中心随机产生一个 半径是1-10的红色实心圆。我们首先自定义一个View对象,CustomView.java: package com.android777.demo.uicontroller.view;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class CustomView extends View {
Paint paint;
List<Dot> dots;
public CustomView(Context context) {
super(context);
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void init(){
paint = new Paint();
//设置绘制的颜色是红色
paint.setColor(Color.RED);
paint.setAntiAlias(true);
//视图对象背景色是蓝色
setBackgroundColor(Color.BLUE);
//初始化时里面没有显示任何的红点
dots = new ArrayList<CustomView.Dot>();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//获取随机点击位置的坐标值
float x = event.getX();
float y = event.getY();
//生成一个随机半径值范围是1 - 10
float radius = (float) (1 + Math.random() * 9);
//将点击的坐标和随机生成的半径值构造成Dot对象存放到视图里
dots.add(new Dot(x,y,radius));
//掉用这个方法 重新绘制视图, 这样就能把上面刚添加的点显示出来
invalidate();
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
//绘制所有视图对象里保存的Dot点信息
for(Dot dot : dots){
canvas.drawCircle(dot.x, dot.y, dot.radius, paint);
}
}
/**
*
* 这个静态内部类用来封装一个红色圆点的位置和半径
*
*/
static class Dot {
public float x;
public float y;
public float radius;
public Dot(float x,float y,float radius){
this.x = x;
this.y = y;
this.radius = radius;
}
}
}
然后我们编写一个Activity,在里面使用上面自定义的视图,CustomViewActivity.java: package com.android777.demo.uicontroller.view;
import android.app.Activity;
import android.os.Bundle;
public class CustomViewActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new CustomView(this));
}
}
运行后,点击屏幕中的某点就会产生一个随机半径范围是1-10的红色小实心圆:
|
|