android 自定义View过程解析

PS:本篇文章大多数翻译自github上一篇英文文章!

总所周知,安卓UI是基于View(屏幕上的单一节点)和ViewGroup(屏幕上节点的集合),在android中有很多widgets和layouts可以用于创建UI界面,比如最常见的View有Button,TextView等等,而最常见的布局也有RelativeLayout,LinearLayout等。

在一些应用中我们不得不自定义View去满足我们的需求,自定义View可以继承一个View或者已存在的子类去创建我们自己的自定义View,甚至可以用SurfaceView去做更复杂的绘图。

创建一个自定义View的一般步骤是继承View或者其子类,重写一些方法比如onDraw,onMeasure,onLayout,onTouchEvent,然后再activity中使用我们的自定义View。

我们主要是通过以下五个方面创建一个自定义View 1,绘图,通过重写onDraw方法控制View在屏幕上的渲染效果 2,交互,通过重写onTouchEvent方法或者使用手势来控制用户的交互 3,测量,通过重写onMeasure方法来对控件进行测量 4,属性,可以通过xml自定义控件的属性,然后通过TypedArray来进行使用 5,状态的保存,为了避免配置改变时丢失View状态,通过重写onSaveInstanceState,onRestoreInstanceState方法来保存和恢复状态

可能这样说比较笼统,我们通过一个例子来进一步了解,假设我们需要一个View允许用户选择不同的形状,而这个控件只会显示一些简单的形状,比如正方形,圆形,三角形,通过点击图形能够在不同形状之间切换。先看下效果图,不断点击进行切换。

一、定义自定义View的类。 为了创建点击可切换的形状的自定义View,我们继承View,编写构造方法。实现三个构造方法,最终调用三个参数的构造方法。

{public CustomView(Context context) {this(context, null);}public CustomView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CustomView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}}

二、把自定义View加入到Layout中。

==”vertical” ><cn.edu.zafu.view.CustomView=”wrap_content”android:layout_centerInParent=”true”/></RelativeLayout>

三、定义自定义属性。 一个良好的自定义控件应该是能通过xml进行控制的,所以我们需要考虑一下我们的自定义View的哪些属性需要被提取到xml中,比如,我们应该可以让用户选择图形的颜色,是否显示图形的名称等。我们可以通过下面的代码在xml中进行配置

<cn.edu.zafu.view.CustomView=”#7f0000″ />

为了能够使用图形的颜色和图形显示的名字的属性,我们应该新建res/values/attrs.xml文件,在里面定义这些属性

===></resources>

注意上述代码,我们为每一个attr节点都写了name属性和format属性,format是属性的数据结构,合法的值包括string, color, dimension, boolean, integer, float, enum等

一旦我们定义了自定义属性,我们就可以在xml文件里进行使用,唯一的区别就是我们自定义属性的命名空间是不同的,我们需要在布局的根节点上或者自定义View上定义命名空间,然后才能使用自定义属性。这里我直接在View上定义命名空间,完全可以把命名空间提取到根布局上。

四、应用自定义属性。 现在我们已经通过xml设定了自定义属性shapeColor和displayShapeName,我们需要在构造方法中提取到这些属性。为了提取属性,我们使用TypedArray类和obtainStyledAttributes方法。

{private int shapeColor;private boolean displayShapeName;public CustomView(Context context) {this(context, null);}public CustomView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CustomView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);setupAttributes(attrs);}(AttributeSet attrs) {// 提取自定义属性到TypedArray对象中TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs,R.styleable.CustomView, 0, 0);// 将属性赋值给成员变量try {shapeColor = a.getColor(R.styleable.CustomView_shapeColor,Color.BLACK);displayShapeName = a.getBoolean(R.styleable.CustomView_displayShapeName, false);} finally {// TypedArray对象是共享的必须被重复利用。a.recycle();}}}

五、增加属性的getter和setter方法

() {return displayShapeName; } (boolean state) {this.displayShapeName = state;invalidate();//重绘requestLayout(); } () {return shapeColor; } (int color) {this.shapeColor = color;invalidate();requestLayout(); }

注意以上代码,当View的属性发生改变时我们需要进行重绘和重新布局,为了保证正常进行,,请确保调用了invalidate和requestLayout方法。

六、绘制图形 接下来,让我们开始真正使用自定义属性(颜色,是否显示图形名)进行图形的绘制。所有的View的绘制发生在onDraw方法里,我们使用其参数Canvas将图形绘制到View上,现在我们绘制一个正方形。

{private int shapeWidth = 100;private int shapeHeight = 100;private int textXOffset = 0;private int textYOffset = 30;private Paint paintShape;private int currentShapeIndex = 0;public CustomView(Context context) {this(context, null);}public CustomView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CustomView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);setupAttributes(attrs);setupPaint();}() {paintShape = new Paint();paintShape.setStyle(Style.FILL);paintShape.setColor(shapeColor);paintShape.setTextSize(30);}}

以上代码会绘制我们定义的颜色的图形,如果显示图形名,其图形名也会被显示,效果图就跟上面的gif图片里的正方形一样。

开始的时侯,我们就知道,总会有终结。

android 自定义View过程解析

相关文章:

你感兴趣的文章:

标签云: