这篇文章是一个自定义View的学习总结文章,会介绍自定义view的整体流程和部分相关的api使用,并不会对所有使用到的api进行介绍,所以阅读的话需要有一些Android的开发基础。
Google为Android开发者提供了非常多的控件,常用的有Button
/TextView
/ImageView
/EditText
等, 日常的开发中大部分场景都可以使用这些基础控件完成UI相关的需求。 可是在很多时候设计师都会拿着ios的手机,来让你实现ios上一样的效果 😫,这是以前比较头疼的一个问题,深入了解自定义View后,感觉以后应该不会再有这样的困扰了。
系统绘制View的顺序
先看看系统提供的组件是怎么绘制出来的, 下面的这段源码是系统绘制View的部分关键代码:
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
/**
* 去掉无关代码
*/
/**
* Manually render this view (and all of its children) to the given Canvas.
* The view must have already done a full layout before this function is
* called. When implementing a view, implement
* {@link #onDraw(android.graphics.Canvas)} instead of overriding this method.
* If you do need to override this method, call the superclass version.
*
* @param canvas The Canvas to which the View is rendered.
*/
@CallSuper
public void draw(Canvas canvas) {
//draw 方法负责调度绘制顺序,先画什么再画什么等
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
*/
//....
// 常用到的覆盖方法有如下几个,顺序如果
drawBackground(canvas);
onDraw(canvas);
dispatchDraw(canvas);
onDrawForeground(canvas);
//....
}
}
draw()
负责调度绘制顺序,通过复写不同方法实现不同的覆盖效果
-
drawBackground()
绘制背景 (需要注意的是drawBackground()
不能重写) -
onDraw()
绘制view的主体部分 -
dispatchDraw()
绘制view的子类 -
onDrawForeground()
绘制view的前景
他们的层级关系是这样的:
![](https://img.haomeiwen.com/i16394208/8a4546cb858f4c17.png)
大部分情况下,复写onDraw()
方法就可以满足我们的需求了,当然一些特殊的情况下,也可以根据具体的需求来决定复写哪个函数
自定义View
- 如何自定义一个View
- 自定义View 可以
extends View
, 或者扩展系统已有的View,例如extends TextView
等 - 重写
onDraw
方法(或者dispatchDraw
/onDrawForeground
)
/**
* 一个自定义的View
*/
public class CustomView extends View {
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 简单的显示一行文字打印
canvas.drawText("Hello CustomView", 50, 100, paint);
}
}
- View的绘制是通过使用
Canvas
和Paint
来完成,
其中Canvas.drawXXX()
是自定义绘制最基本的操作
-Canvas.drawColor(@ColorInt int color)
设置绘制的背景色
drawColor(Color.BLACK); // 纯黑
![](https://img.haomeiwen.com/i16394208/6c9ffb7dfe3b414c.png)
-canvas.drawText()
绘制文字
text = "Hello Word!";
paint.setTextSize(60);
paint.setColor(Color.RED);
canvas.drawText(text, 50, 100, paint);
![](https://img.haomeiwen.com/i16394208/f1782dc55eb5248b.png)
可以通过setTextSkewX(倾斜)/setUnderlineText(下划线)/setStrikeThruText(删除线)等相关方法来设置文字的不同显示
-canvas.drawCircle()
文字几何图形
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(0);
canvas.drawCircle(300f,50f, 50f, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(450f,50f, 50f, mPaint);
// FILL 为填充
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLUE);
canvas.drawCircle(300f,200f, 50f, mPaint);
// STROKE 为不填充,空心圆
mPaint.setStyle(Paint.Style.STROKE);
//设置颜色 。
mPaint.setColor(Color.BLACK);
//设置填充样式
mPaint.setStyle(Paint.Style.STROKE);
// 设置外框的大小
mPaint.setStrokeWidth(20);
canvas.drawCircle(450f,200f, 50f, mPaint);
![](https://img.haomeiwen.com/i16394208/29d54385cc2ec2b8.png)
绘制图片等和绘制几何图形类似,使用
drawBitmap()
方法。
其中几何图形和图片等,可以进行移动/缩放/旋转 等变化, 具体等变化太多,这里就不一一列举,需要可以去查看上面的参考文章。
学会了 drawxxx() 的方法,就可以绘制如下的表格等就不是问题了:
![](https://img.haomeiwen.com/i16394208/21466642de78c1ec.png)
// 这只是 demo 代码,图和代码有部分差异
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int pointX = (int)(getWidth() * 0.11f);
int pointY = (int)(getHeight() * 0.7f);
mPaint.setAntiAlias(true);
mPath.moveTo(pointX,20);
mPath.lineTo(pointX, pointY);
mPath.rLineTo((int)(getWidth() * 0.8f), 0);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(3);
canvas.drawPath(mPath, mPaint);
mPaint.setTextSize(42);
canvas.drawText(NAME, getWidth() / 2 - 50, getHeight() - (int)(getHeight() * 0.15f), mPaint);
mPaint.setTextSize(30);
for (int i = 0; i < nameList.length; i++) {
int x = pointX + ((i+1) * OFFSET_RECT) + i * RECT_WIDTH;
if (i == 0) {
x = pointX + OFFSET_RECT;
}
canvas.drawText(nameList[i], x, pointY + 30, mPaint);
}
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.GREEN);
for (int i = 0; i < nameList.length; i++) {
int x = pointX + ((i+1) * OFFSET_RECT) + i * RECT_WIDTH;
if (i == 0) {
x = pointX + OFFSET_RECT;
}
int height = random.nextInt(300);
canvas.drawRect(x,(pointY - height), x + RECT_WIDTH, pointY, mPaint);
}
}
![](https://img.haomeiwen.com/i16394208/eeaf2d80b3b94a09.png)
// 这只是 demo 代码,图和代码有部分差异
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setTextSize(30);
canvas.drawText("Lollipop", 100, 100, mPaint);
// canvas.drawLine(100, 100, mPaint);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.RED);
canvas.drawArc(rectFFirst,180, 120, true, mPaint);
mPaint.setColor(Color.BLUE);
canvas.drawArc(rectFSecond,80, 100, true, mPaint);
mPaint.setColor(Color.GREEN);
canvas.drawArc(rectFSecond,40, 38, true, mPaint);
mPaint.setColor(Color.GRAY);
canvas.drawArc(rectFSecond,20, 18, true, mPaint);
mPaint.setColor(Color.WHITE);
canvas.drawArc(rectFSecond,0, 18, true, mPaint);
mPaint.setColor(Color.YELLOW);
canvas.drawArc(rectFSecond,-60, 60, true, mPaint);
}
网友评论