android-可移动的标签

虽说可移动的标签没什么难度可言, 但对于些自定义view相对薄弱的来讲, 还是有点意义的, 比如说我.

先看下我这边的效果图吧.

lableView

整个绘制过程相对比较简单.

首先onMessage中测量要具体显示的位置, 或者说能显示的大小是多少

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
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width, height;
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY) {
width = Math.max(widthSize, mixWidth); //widthSize > mixWidth ? widthSize : mixWidth;
} else {
width = getPaddingLeft() + mixWidth + getPaddingRight();
}
if (heightMode == MeasureSpec.EXACTLY) {
height = Math.max(heightSize, mixHeight);//heightSize > mixHeight ? heightSize : mixHeight;
} else {
height = getPaddingTop() + mixHeight + getPaddingBottom();
}
mCircleY = height / 2;
setMeasuredDimension(width, height);
}

绘制细线

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
/**
* 绘制细线
*
* @param canvas
*/
private void drawLine(Canvas canvas) {
if (mStrs.length == 0) return;
mLinePaint.setStyle(Paint.Style.STROKE);
reSetPath();
if (mCircleX > getMeasuredHeight() / 2) { // 原点在右侧, 文字需要在左
asLeft = -1;
lineStartX = mCircleX - mRadius * 0.6f;
} else {
asLeft = 1;
lineStartX = mCircleX + mRadius * 0.6f;
}
if (mStrs.length == 1) {
mPath[0].rLineTo((mTextPaint.measureText(mStrs[0]) + disGap / 2) * asLeft + disGap, 0);
canvas.drawPath(mPath[0], mLinePaint);
} else if (mStrs.length == 2) {
mPath[0].lineTo(lineStartX + disGap * asLeft, mCircleY - disGap);
mPath[0].rLineTo((mTextPaint.measureText(mStrs[0]) + disGap / 2) * asLeft, 0);
canvas.drawPath(mPath[0], mLinePaint);
mPath[1].lineTo(lineStartX + disGap * asLeft, mCircleY + disGap);
mPath[1].rLineTo((mTextPaint.measureText(mStrs[1]) + disGap / 2) * asLeft, 0);
canvas.drawPath(mPath[1], mLinePaint);
} else {
mPath[0].lineTo(lineStartX + disGap * asLeft, mCircleY - disGap);
mPath[0].rLineTo((mTextPaint.measureText(mStrs[0]) + disGap / 2) * asLeft, 0);
canvas.drawPath(mPath[0], mLinePaint);
mPath[1].rLineTo((mTextPaint.measureText(mStrs[1]) + disGap * 1.5f) * asLeft, 0);
canvas.drawPath(mPath[1], mLinePaint);
mPath[2].lineTo(lineStartX + disGap * asLeft, mCircleY + disGap);
mPath[2].rLineTo((mTextPaint.measureText(mStrs[2]) + disGap / 2) * asLeft, 0);
canvas.drawPath(mPath[2], mLinePaint);
}
}

设置文字

这里只提供在java代码中设置文字, 个人觉得这样比在xml中更灵活些. 所以提供了可直接设置文字的可变数组(仅支持1-3个文字标签)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 设置文字
*
* @param str 要显示的文字
*/
public void setText(String... str) {
if (str.length > 3) {
mStrs[0] = str[0];
mStrs[1] = str[1];
mStrs[2] = str[2];
} else {
this.mStrs = str;
}
invalidate();
}

绘制文字

刚开始是想直接drawTextonPath, 原点在左, 文字在右,倒是好绘制. 但是反过来, 原点在右,文字在左就不好搞了,最终换成直接绘制文字.

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
/**
* 绘制文字
*
* @param canvas
*/
private void drawText(Canvas canvas) {
if (mStrs.length == 0) return;
if (asLeft > 0) { // 原点在左侧, 文字需要在右
mTextPaint.setTextAlign(Paint.Align.LEFT);
} else {
mTextPaint.setTextAlign(Paint.Align.RIGHT);
}
if (mStrs.length == 1) {
canvas.drawText(mStrs[0], lineStartX + disGap * asLeft, mCircleY - mLineDisText, mTextPaint);
} else if (mStrs.length == 2) {
canvas.drawText(mStrs[0], lineStartX + disGap * asLeft, mCircleY - disGap - mLineDisText, mTextPaint);
canvas.drawText(mStrs[1], lineStartX + disGap * asLeft, mCircleY + disGap - mLineDisText, mTextPaint);
} else {
canvas.drawText(mStrs[0], lineStartX + disGap * asLeft, mCircleY - disGap - mLineDisText, mTextPaint);
canvas.drawText(mStrs[1], lineStartX + disGap * asLeft, mCircleY - mLineDisText, mTextPaint);
canvas.drawText(mStrs[2], lineStartX + disGap * asLeft, mCircleY + disGap - mLineDisText, mTextPaint);
}
}

到此一个普通的带标签的view已经绘制好了, 再加些动画就更好看些了

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 初始化动画
*/
private void initAnim() {
mAnimator = ObjectAnimator.ofFloat(this, "progress", 0.6f, 1);
mAnimator.setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
// 无限循环
mAnimator.setRepeatCount(ValueAnimator.INFINITE);
// 重复模式, RESTART: 重新开始 REVERSE:恢复初始状态再开始
mAnimator.setRepeatMode(ValueAnimator.REVERSE);
}

整个过程就是这样,具体详细代码, 可前往Github查看全部代码

Title - Artist
0:00