Android常用代码-自定义View和ViewGroup

  1. 1. 一、自定义View
    1. 1.1. 自定义属性
    2. 1.2. Paint相关
      1. 1.2.1. 设置文字大小
      2. 1.2.2. 获取文字宽度
      3. 1.2.3. 获取文字高度
      4. 1.2.4. 获取文字基线
      5. 1.2.5. 透明度
      6. 1.2.6. 抗锯齿
      7. 1.2.7. 颜色
      8. 1.2.8. 填充样式
      9. 1.2.9. 渐变色
        1. 1.2.9.1. 线性渐变
        2. 1.2.9.2. 弧形渐变
        3. 1.2.9.3. SweepGradient构造方法说明
    3. 1.3. Canvas相关
      1. 1.3.1. 文字
      2. 1.3.2. 圆形
      3. 1.3.3. 圆环
      4. 1.3.4. 矩形
      5. 1.3.5. 圆角矩形
      6. 1.3.6. 扇形
      7. 1.3.7. 贝塞尔曲线
      8. 1.3.8. 直线
      9. 1.3.9. 图片
      10. 1.3.10. 三角形
      11. 1.3.11. 五角星
      12. 1.3.12. 网格
      13. 1.3.13. 动画
  2. 2. 二、自定义ViewGroup
    1. 2.1. onLayout

一、自定义View

自定义属性

  • 以ZzHorizontalProgressBar为例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//attrs.xml
<declare-styleable name="ZzHorizontalProgressBar">
<!--大小-->
<attr name="zpb_padding" format="dimension" />
<!--颜色-->
<attr name="zpb_bg_color" format="color|reference" />
<attr name="zpb_pb_color" format="color|reference" />
<attr name="zpb_second_pb_color" format="color|reference" />
<!--整数-->
<attr name="zpb_max" format="integer" />
<attr name="zpb_progress" format="integer" />
<attr name="zpb_second_progress" format="integer" />
<!--布尔-->
<attr name="zpb_show_second_progress" format="boolean" />
<!--枚举-->
<attr name="zpb_show_second_point_shape" format="enum">
<enum name="point" value="0"/>
<enum name="line" value="1"/>
</attr>
</declare-styleable>
1
2
3
4
5
6
7
8
9
10
11
12
13
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SomeWidgetName);
//整数
int max = a.getInteger(R.styleable.ZzHorizontalProgressBar_zpb_max, 100);
//颜色
int bgColor = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_bg_color, 0xff3F51B5);
//尺寸大小
int padding = a.getDimensionPixelSize(R.styleable.ZzHorizontalProgressBar_zpb_padding, 2);
//布尔类型
boolean showSecondProgress = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_show_second_progress, false);
//枚举
int secondProgressShape = a.getInteger(R.styleable.ZzHorizontalProgressBar_zpb_show_second_point_shape, 0);
//... ...
a.recycle();

Paint相关

设置文字大小

1
mPaint.setTextSize(AutoUtils.getPercentWidthSize(20));

获取文字宽度

1
float textWidth = mPaint.measureText(text);

获取文字高度

1
float textHeight = mPaint.descent() - mPaint.ascent();

获取文字基线

1
2
3
4
5
6
//posX 和 posY 为文字的左上角的坐标
Paint.FontMetrics metrics = new Paint.FontMetrics();
mPaint.getFontMetrics(metrics);
float baseLineY = posY - metrics.top;
//... ...
canvas.drawText(textTop, posX, baseLineY, mPaint);

透明度

1
mPaint.setAlpha(255); //0~255

抗锯齿

1
mPaint.setAntiAlias(true);

颜色

1
mPaint.setColor(Color.WHITE);

填充样式

填充

1
mPaint.setStyle(Paint.Style.FILL);

边框

1
mPaint.setStyle(Paint.Style.STROKE);
1
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);

渐变色

线性渐变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//以画渐变进度条为例
int progressWidth = width - padding * 2;
float mDx = progressWidth * percent;
int colors[] = new int[2];
float positions[] = new float[2];
//渐变开始颜色
colors[0] = gradientFrom;
positions[0] = 0;
//渐变结束颜色
colors[1] = gradientTo;
positions[1] = 1;
LinearGradient shader = new LinearGradient(
padding + progressHeight / 2, padding, padding + progressHeight / 2 + mDx, padding + progressHeight,
colors,
positions,
Shader.TileMode.MIRROR);
//gradient
mPaint.setShader(shader);

LinearGradient构造方法说明

1
public LinearGradient(float x0, float y0,float x1, float y1, int colors[], float positions[],TileMode tile){}
  • x0 渐变线起点的x坐标
  • y0 渐变线起点的y坐标
  • x1 渐变线结束处的x坐标
  • y1 渐变线结束处的y坐标
  • colors 沿渐变线分布的颜色
  • positions 可能为null,颜色数组中每个对应颜色的相对位置[0..1]。如果它为空,则颜色沿梯度线均匀分布
  • tile 着色器平铺模式

弧形渐变

1
2
3
SweepGradient shader = new SweepGradient(getWidth() / 2, getHeight() / 2, startProgressColor, endProgressColor);
//gradient
progressPaint.setShader(shader);

SweepGradient构造方法说明

1
public SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1) {}
  • cx 中心的x坐标
  • cy 中心的y坐标
  • color0 在扫描开始时使用的颜色
  • color1 扫描结束时使用的颜色

Canvas相关

文字

1
canvas.drawText(textTop, posX, baseLineY, mPaint);

方法说明

1
public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint){}
  • text 要绘制的文本
  • x 正在绘制的文本原点的x坐标
  • y 正在绘制的文本的基线的y坐标,注意是baseLine的坐标
  • paint 用于绘制文本的画笔

圆形

1
2
3
//设置实心
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(padding + s_progressHeight / 2, padding + s_progressHeight / 2, s_progressHeight / 2, mPaint);

圆环

1
2
3
4
5
//设置空心
mPaint.setStyle(Paint.Style.STROKE);
//设置环厚
mPaint.setStrokeWidth(10f);
canvas.drawCircle(padding + s_progressHeight / 2, padding + s_progressHeight / 2, s_progressHeight / 2, mPaint);

方法说明

1
public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint){}
  • cx 要绘制的圆的中心的x坐标
  • cy 要绘制的圆的中心的y坐标
  • radius 要绘制的圆的半径
  • paint 用于绘制圆的画笔

矩形

圆角矩形

扇形

1
canvas.drawArc(outRect, mData.getStartAngle(), mData.getSwipeAngle(), true, mPaint);

方法说明

1
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}
  • oval 椭圆的边界用于定义弧的形状和大小
  • startAngle 圆弧开始的起始角度(以度为单位)
  • sweepAngle 扫描角度(以度为单位)顺时针测量
  • useCenter 如果为true,则将椭圆的中心包含在弧中,如果为false,则将其关闭。这将画一个楔子
  • paint 用于绘制弧线的画笔

贝塞尔曲线

直线

1
2
3
4
//垂直直线
canvas.drawLine(x, 0, x, getHeight(), paint);
//水平直线
canvas.drawLine(0, y, getWidth(), y, paint);

图片

三角形

1
2
3
4
5
6
Path path = new Path();
path.moveTo(centerX, AutoUtils.getPercentHeightSize(20));// 此点为多边形的起点
path.lineTo(centerX-AutoUtils.getPercentWidthSize(30), 0);
path.lineTo(centerX+AutoUtils.getPercentWidthSize(30), 0);
path.close(); // 使这些点构成封闭的多边形
c.drawPath(path, paint);

五角星

网格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void drawGrid(Canvas canvas) {
int width = getWidth();
int height = getHeight();
int rectWidth = width / totalColumn;
int rectHeight = height / totalRow;

int posY = 1;
canvas.drawLine(0, posY, getWidth(), posY, gridPaint);
for (int i = 1; i <= totalRow; i++) {
posY = i * rectHeight;
canvas.drawLine(0, posY, getWidth(), posY, gridPaint);
}
int posX = 1;
canvas.drawLine(posX, 0, posX, getHeight(), gridPaint);
for (int i = 1; i <= totalColumn; i++) {
posX = i * rectWidth;
canvas.drawLine(posX, 0, posX, getHeight(), gridPaint);
}
}

动画

二、自定义ViewGroup

onLayout