0%

Android自定义View

一、简述

  • 或多或少老哥们都了解自定义View是啥,本篇文章选了一个比较简单的例子来当做示例,希望大佬们能够喜欢。
  • 知识点:自定义属性attrs的简单使用,通过继承View重写onDraw方法使用Canvas来绘制,关于Canvas的用法和View基础可以看我前面写的文章。

二、重写onDraw方法

在开始之前,默认老哥您了解Canvas及View的位置参数,如果不了解请到我的博客瞅一眼。

我在处理边距时是将多余的区域平分放到了两侧,也就是相当于内容居中,详细内容可以看代码,注释很详细。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

// 获取宽度与高度
int width = getWidth();
int height = getHeight();
//圆的个数
int count;
try {
// 计算可以显示多少个圆
count = (width - gap) / (radius * 2 + gap);
} catch (Exception e) {
count = 0;
Log.e(TAG, "onDraw: ", e);
}
// 圆的直径
int h = (radius * 2);
// 圆以外的长度
int cgap = (width - (count * h));
// 两侧端点的长度,
int x1 = (cgap + gap - (gap * count)) / 2;
// 绘制
for (int i = 0; i < count; i++) {
int x = x1 + radius + (h + gap) * i;
canvas.drawCircle(x, 0, radius, mPaint);
canvas.drawCircle(x, height, radius, mPaint);
}
}

三、供外部类操作属性的公有方法

1
2
3
4
5
6
7
8
9
10
// 读取圆的半径
public int getRadius() {
return Utils.px2dp(mContext, radius);
}
// 设置圆的半径
public void setRadius(int radius) {
this.radius = Utils.dp2px(mContext, radius);
// 刷新视图
invalidate();
}

四、View自定义属性

  1. 创建属性文件(res/values/attrs.xml)

    1
    2
    3
    4
    5
    6
    7
    8
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <declare-styleable name="ViewZ2View">
    <attr name="circle_color" format="color" />
    <attr name="radius" format="dimension" />
    <attr name="gap" format="dimension" />
    </declare-styleable>
    </resources>
    1. 上面的XML文件声明了一个名字为ViewZ2View的自定义属性集合。
    2. name是自定义属性的名字。
    3. format是自定义属性的类型,color是颜色属性,integer是基本数据类型,除此之外还有很多,可以阅读文档或直接使用as的代码提示。
  2. 在布局文件中添加属性

    1
    2
    3
    4
    5
    6
    7
    xmlns:app="http://schemas.android.com/apk/res-auto"
    ... ...
    <com.sdwfqin.sample.view.viewz2.ViewZ2View
    ... ...
    app:circle_color="#ffffff"
    app:gap="10dp"
    app:radius="10dp" />
  3. 在代码中读取设置的属性

1
2
3
4
5
6
7
8
9
private void init(Context context, @Nullable AttributeSet attrs) {
// 加载自定义属性集合
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ViewZ2View);
// Color.WHITE为默认颜色
mColor = typedArray.getColor(R.styleable.ViewZ2View_circle_color, Color.WHITE);
radius = typedArray.getDimensionPixelSize(R.styleable.ViewZ2View_radius, radius);
gap = typedArray.getDimensionPixelSize(R.styleable.ViewZ2View_gap, gap);
typedArray.recycle();
}

五、示例代码

  1. Java文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    public class ViewZ2View extends LinearLayout {

    private static final String TAG = "ViewZ2View";
    private Context mContext;
    private int mColor = Color.WHITE;
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    // 要提高精度可以使用float
    //圆的半径
    private int radius = 10;
    //圆之间的间距
    private int gap = 10;

    public ViewZ2View(Context context) {
    super(context);
    init(context);
    }

    public ViewZ2View(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs);
    }

    public ViewZ2View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs);
    }

    private void init(Context context) {
    mContext = context;
    mPaint.setColor(mColor);
    gap = Utils.dp2px(context, 10);
    }

    private void init(Context context, @Nullable AttributeSet attrs) {
    mContext = context;
    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ViewZ2View);
    // Color.WHITE为默认颜色
    mColor = typedArray.getColor(R.styleable.ViewZ2View_circle_color, Color.WHITE);
    radius = typedArray.getDimensionPixelSize(R.styleable.ViewZ2View_radius, radius);
    gap = typedArray.getDimensionPixelSize(R.styleable.ViewZ2View_gap, gap);
    typedArray.recycle();
    mPaint.setColor(mColor);
    }

    public int getColor() {
    return mColor;
    }

    public void setColor(int color) {
    this.mColor = color;
    mPaint.setColor(mColor);
    // 刷新视图
    invalidate();
    }
    // 读取圆的半径
    public int getRadius() {
    return Utils.px2dp(mContext, radius);
    }
    // 设置圆的半径
    public void setRadius(int radius) {
    this.radius = Utils.dp2px(mContext, radius);
    // 刷新视图
    invalidate();
    }

    public int getGap() {
    return Utils.px2dp(mContext, gap);
    }

    public void setGap(int gap) {
    this.gap = Utils.dp2px(mContext, gap);
    invalidate();
    }

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

    // 获取宽度与高度
    int width = getWidth();
    int height = getHeight();
    //圆的个数
    int count;
    try {
    // 计算可以显示多少个圆
    count = (width - gap) / (radius * 2 + gap);
    } catch (Exception e) {
    count = 0;
    Log.e(TAG, "onDraw: ", e);
    }
    // 圆的直径
    int h = (radius * 2);
    // 圆以外的长度
    int cgap = (width - (count * h));
    // 两侧端点的长度,
    int x1 = (cgap + gap - (gap * count)) / 2;
    // 绘制
    for (int i = 0; i < count; i++) {
    int x = x1 + radius + (h + gap) * i;
    canvas.drawCircle(x, 0, radius, mPaint);
    canvas.drawCircle(x, height, radius, mPaint);
    }
    }
    }
  2. xml文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <com.sdwfqin.sample.view.viewz2.ViewZ2View
    android:id="@+id/viewz2_main"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_margin="20dp"
    android:background="@color/bar"
    android:gravity="center"
    app:circle_color="#ffffff"
    app:gap="10dp"
    app:radius="10dp">

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="抽奖券" />
    </com.sdwfqin.sample.view.viewz2.ViewZ2View>

六、源码地址

https://github.com/sdwfqin/AndroidSamples