android自定义控件

  • 1、坐标系

  • 屏幕默认坐标系示例View坐标系get雨getRaw区别
  • 分类和流程

  • 自定义View绘制流程函数调用链

几个重要的函数

1.构造函数css

构造函数是View的入口,能够用于初始化一些的内容,和获取自定义属性java

View的构造函数有四种重载分别以下:android

public void SloopView(Context context) {} public void SloopView(Context context, AttributeSet attrs) {} public void SloopView(Context context, AttributeSet attrs, int defStyleAttr) {} public void SloopView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {} 

有三个参数的构造函数中第三个参数是默认的Style,这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style,且只有在明确调用的时候才会生效,以系统中的ImageButton为例说明:canvas

public ImageButton(Context context, AttributeSet attrs) { //调用了三个参数的构造函数,明确指定第三个参数 this(context, attrs, com.android.internal.R.attr.imageButtonStyle); } public ImageButton(Context context, AttributeSet attrs, int defStyleAttr) { //此处调了四个参数的构造函数,无视便可 this(context, attrs, defStyleAttr, 0); }

排除了两个以后,只剩下一个参数和两个参数的构造函数,他们的详情以下:ide

//通常在直接New一个View的时候调用。 public void SloopView(Context context) {} //通常在layout文件中使用的时候会调用,关于它的全部属性(包括自定义属性)都会包含在attrs中传递进来。 public void SloopView(Context context, AttributeSet attrs) {} 

如下方法调用的是一个参数的构造函数:函数

//在Avtivity中 SloopView view new SloopView(this); 

如下方法调用的是两个参数的构造函数:oop

//在layout文件中 - 格式为: 包名.View名 <com.sloop.study.SloopView android:layout_width"wrap_content" android:layout_height"wrap_content"/> 

2.测量View大小(onMeasure)布局

View的大小不只由自身所决定,同时也会受到父控件的影响,为了咱们的控件能更好的适应各类状况,通常会本身进行测量。this

测量View大小使用的是onMeasure函数,咱们能够从onMeasure的两个参数中取出宽高的相关数据:spa

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthsize = MeasureSpec.getSize(widthMeasureSpec); //取出宽度的确切数值 int widthmode = MeasureSpec.getMode(widthMeasureSpec); //取出宽度的测量模式 int heightsize = MeasureSpec.getSize(heightMeasureSpec); //取出高度的确切数值 int heightmode = MeasureSpec.getMode(heightMeasureSpec); //取出高度的测量模式 } 

从上面能够看出 onMeasure 函数中有 widthMeasureSpec 和 heightMeasureSpec 这两个 int 类型的参数, 毫无疑问他们是和宽高相关的, 但它们其实不是宽和高, 而是由宽、高和各自方向上对应的测量模式来合成的一个值:

测量模式一共有三种, 被定义在 Android 中的 View 类的一个内部类View.MeasureSpec中:

模式 二进制数值 描述
UNSPECIFIED 00 默认值,父控件没有给子view任何限制,子View能够设置为任意大小。
EXACTLY 01 表示父控件已经确切的指定了子View的大小。
AT_MOST 10 表示子View具体大小没有尺寸限制,可是存在上限,上限通常为父View大小。

 

用 MeasureSpec 的 getSize是获取数值, getMode是获取模式。

注意:

若是对View的宽高进行修改了,不要调用 super.onMeasure( widthMeasureSpec, heightMeasureSpec); 要调用 setMeasuredDimension( widthsize, heightsize)这个函数。

3.肯定View大小(onSizeChanged)

这个函数在视图大小发生改变时调用。

由于View的大小不只由View自己控制,并且受父控件的影响,因此咱们在肯定View大小的时候最好使用系统提供的onSizeChanged回调函数。

onSizeChanged以下:

@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } 

四个参数,分别为 宽度,高度,上一次宽度,上一次高度。

只需关注 宽度(w), 高度(h) 便可,这两个参数就是View最终的大小。

4.肯定子View布局位置(onLayout)

肯定布局的函数是onLayout,它用于肯定子View的位置,在自定义ViewGroup中会用到,他调用的是子View的layout函数。

在自定义ViewGroup中,onLayout通常是循环取出子View,而后通过计算得出各个子View位置的坐标值,而后用如下函数设置子View位置。

child.layout(l, t, r, b); 

5.绘制内容(onDraw)

onDraw是实际绘制的部分,也就是咱们真正关心的部分,使用的是Canvas绘图。

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); }

6.对外提供操做方法和监听回调

自定义完View以后,通常会对外暴露一些接口,用于控制View的状态等,或者监听View的变化.

  • 3、Canvas

操做类型

相关API

备注

绘制颜色

drawColor, drawRGB, drawARGB

使用单一颜色填充整个画布

绘制基本形状

drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc

依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧

绘制图片

drawBitmap, drawPicture

绘制位图和图片

绘制文本

drawText, drawPosText, drawTextOnPath

依次为 绘制文字、绘制文字时指定每一个文字位置、根据路径绘制文字

绘制路径

drawPath

绘制路径,绘制贝塞尔曲线时也须要用到该函数

顶点操做

drawVertices, drawBitmapMesh

经过对顶点操做可使图像形变,drawVertices直接对画布做用、 drawBitmapMesh只对绘制的Bitmap做用

画布剪裁

clipPath, clipRect

设置画布的显示区域

画布快照

save, restore, saveLayerXxx, restoreToCount, getSaveCount

依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数

画布变换

translate, scale, rotate, skew

依次为 位移、缩放、 旋转、错切

Matrix(矩阵)

getMatrix, setMatrix, concat

实际上画布的位移,缩放等操做的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些经常使用的方法。

    private Paint mPaint = new Paint();初始化画笔

    private void initPaint() {

      mPaint.setColor(Color.BLACK);//设置画笔颜色

      mPaint.setStyle(Paint.Style.FILL);//设置画笔模式为填充

      mPaint.setStrokeWidth(10f); //设置画笔宽度为10px

    }

    public SloopView(Context context, AttributeSet attrs) {

      super(context, attrs); initPaint();

    }

绘制点:       canvas.drawPoint(200, 200, mPaint);

绘制线:       canvas.drawLine(300,300,500,600,mPaint);

绘制矩形:  canvas.drawRect(100,100,800,400,mPaint);

               Rect rect = new Rect(100,100,800,400); canvas.drawRect(rect,mPaint);

       RectF rectF = new RectF(100,100,800,400); canvas.drawRect(rectF,mPaint);

绘制圆:       canvas.drawCircle(500,500,400,mPaint);

绘制圆弧:  public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint){}

4、注意事项:

一、在 xml中建立了一个view时,全部在xml中声明的属性都会被传入到view的构造方法中的AttributeSet类型的参数当中。 经过调用Context的obtainStyledAttributes()方法返回一个TypedArray对象。而后直接用TypedArray对象获取自定义属性的值。TypedArray对象是共享的资源,因此在获取完值以后必需要调用recycle()方法来回收

二、自定义控件的属性发生改变以后,控件的样子也可能发生改变,在这种状况下就须要调用invalidate()方法让系统去调用view的onDraw()从新绘制

三、在onDraw方法中开始绘制以前,应该让画笔Paint对象的信息初始化完毕。这是由于View的从新绘制是比较频繁的,这就可能屡次调用onDraw,因此初始化的代码不该该放在onDraw方法里


 参考:http://www.gcssloop.com/customview/CustomViewIndex
相关文章
相关标签/搜索