虽说可移动的标签没什么难度可言, 但对于些自定义view相对薄弱的来讲, 还是有点意义的, 比如说我.
先看下我这边的效果图吧.
整个绘制过程相对比较简单.
首先onMessage中测量要具体显示的位置, 或者说能显示的大小是多少
@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 / ;
setMeasuredDimension(width, height);
}
绘制细线
/**
* 绘制细线
*
* @param canvas
*/
private void drawLine(Canvas canvas) {
if (mStrs.length == ) return;
mLinePaint.setStyle(Paint.Style.STROKE);
reSetPath();
if (mCircleX > getMeasuredHeight() / ) { // 原点在右侧, 文字需要在左
asLeft = -;
lineStartX = mCircleX - mRadius * f;
} else {
asLeft = ;
lineStartX = mCircleX + mRadius * f;
}
if (mStrs.length == ) {
mPath[].rLineTo((mTextPaint.measureText(mStrs[]) + disGap / ) * asLeft + disGap, );
canvas.drawPath(mPath[], mLinePaint);
} else if (mStrs.length == ) {
mPath[].lineTo(lineStartX + disGap * asLeft, mCircleY - disGap);
mPath[].rLineTo((mTextPaint.measureText(mStrs[]) + disGap / ) * asLeft, );
canvas.drawPath(mPath[], mLinePaint);
mPath[].lineTo(lineStartX + disGap * asLeft, mCircleY + disGap);
mPath[].rLineTo((mTextPaint.measureText(mStrs[]) + disGap / ) * asLeft, );
canvas.drawPath(mPath[], mLinePaint);
} else {
mPath[].lineTo(lineStartX + disGap * asLeft, mCircleY - disGap);
mPath[].rLineTo((mTextPaint.measureText(mStrs[]) + disGap / ) * asLeft, );
canvas.drawPath(mPath[], mLinePaint);
mPath[].rLineTo((mTextPaint.measureText(mStrs[]) + disGap * f) * asLeft, );
canvas.drawPath(mPath[], mLinePaint);
mPath[].lineTo(lineStartX + disGap * asLeft, mCircleY + disGap);
mPath[].rLineTo((mTextPaint.measureText(mStrs[]) + disGap / ) * asLeft, );
canvas.drawPath(mPath[], mLinePaint);
}
}
设置文字
这里只提供在java代码中设置文字, 个人觉得这样比在xml中更灵活些. 所以提供了可直接设置文字的可变数组(仅支持1-3个文字标签)
/**
* 设置文字
*
* @param str 要显示的文字
*/
public void setText(String... str) {
if (str.length > ) {
mStrs[] = str[];
mStrs[] = str[];
mStrs[] = str[];
} else {
this.mStrs = str;
}
invalidate();
}
绘制文字
刚开始是想直接drawTextonPath, 原点在左, 文字在右,倒是好绘制. 但是反过来, 原点在右,文字在左就不好搞了,最终换成直接绘制文字.
/**
* 绘制文字
*
* @param canvas
*/
private void drawText(Canvas canvas) {
if (mStrs.length == ) return;
if (asLeft > ) { // 原点在左侧, 文字需要在右
mTextPaint.setTextAlign(Paint.Align.LEFT);
} else {
mTextPaint.setTextAlign(Paint.Align.RIGHT);
}
if (mStrs.length == ) {
canvas.drawText(mStrs[], lineStartX + disGap * asLeft, mCircleY - mLineDisText, mTextPaint);
} else if (mStrs.length == ) {
canvas.drawText(mStrs[], lineStartX + disGap * asLeft, mCircleY - disGap - mLineDisText, mTextPaint);
canvas.drawText(mStrs[], lineStartX + disGap * asLeft, mCircleY + disGap - mLineDisText, mTextPaint);
} else {
canvas.drawText(mStrs[], lineStartX + disGap * asLeft, mCircleY - disGap - mLineDisText, mTextPaint);
canvas.drawText(mStrs[], lineStartX + disGap * asLeft, mCircleY - mLineDisText, mTextPaint);
canvas.drawText(mStrs[], lineStartX + disGap * asLeft, mCircleY + disGap - mLineDisText, mTextPaint);
}
}
到此一个普通的带标签的view已经绘制好了, 再加些动画就更好看些了
/**
* 初始化动画
*/
private void initAnim() {
mAnimator = ObjectAnimator.ofFloat(this, "progress", f, );
mAnimator.setDuration();
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
// 无限循环
mAnimator.setRepeatCount(ValueAnimator.INFINITE);
// 重复模式, RESTART: 重新开始 REVERSE:恢复初始状态再开始
mAnimator.setRepeatMode(ValueAnimator.REVERSE);
}