我blog也寫過卖擅,歡迎各位看我博客,https://blog.csdn.net/qq_24675479
首先看下效果圖
在做這個(gè)項(xiàng)目之前先了解下文字獲取
我上一篇 自定義View入門 - 自定義TextView 有寫過——http://www.reibang.com/p/7b5e4f5abb74
今天詳細(xì)講解一下baseLine 基線(參考文章:文淑大神的自定義View之繪圖篇(四)http://blog.csdn.net/u012551350/article/details/51361778)
FontMetrics
top:可繪制的最高高度所在線
bottom:可繪制的最低高度所在線
ascent :系統(tǒng)建議的篙顺,繪制單個(gè)字符時(shí)政基,字符應(yīng)當(dāng)?shù)淖罡吒叨人诰€
descent:系統(tǒng)建議的示辈,繪制單個(gè)字符時(shí)凑兰,字符應(yīng)當(dāng)?shù)淖畹透叨人诰€
獲取實(shí)例
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
Paint.FontMetricsInt fm= mPaint.getFontMetricsInt();
成員變量
float ascent = fontMetrics.ascent;
float descent = fontMetrics.descent;
float top = fontMetrics.top;
float bottom = fontMetrics.bottom;
float leading = fontMetrics.leading;
這里的ascent掌桩,descent,top姑食,bottom波岛,leading指的是到基線baseline的位置
[圖片上傳失敗...(image-4386fb-1530855738868)]
文字的高度
float top = fontMetrics.top + baseLineY;
float bottom = fontMetrics.bottom + baseLineY;
//文字高度
float height= bottom - top; //注意top為負(fù)數(shù)
//文字中點(diǎn)y坐標(biāo)
float center = (bottom - top) / 2;
即中線是(bottom-top)/2,實(shí)際呢是bottom+top只是因?yàn)檫@里的top是負(fù)的(圖片上的top到baseline的距離)
已知中線求baseline
[圖片上傳失敗...(image-9ea4bc-1530855738868)]
結(jié)論
baseline=centerY+A-fm.bottom;
centerY呢實(shí)際就是getHeight/2,整體高度的一半音半,然后求基線的y坐標(biāo)则拷,實(shí)際就是(top-bottom)/2-fontMetrics.bottom;再次強(qiáng)調(diào):這里的ascent,descent曹鸠,top煌茬,bottom,leading指的是到基線baseline的位置彻桃。最后相加getHeight+(top-bottom)/2-fontMetrics.bottom**
接下來開始做項(xiàng)目:
- 第一步自定義屬性
一共需要:內(nèi)部圓環(huán)顏色宣旱,外部圓環(huán)顏色,圓環(huán)寬度叛薯,文字顏色,文字大小五種
<declare-styleable name="QQStepView">
<attr name="outerColor" format="color" />
<attr name="innerColor" format="color" />
<attr name="borderWidth" format="dimension" />
<attr name="stepTextSize" format="dimension" />
<attr name="stepTextColor" format="color" />
</declare-styleable>
- 自定義view獲取屬性笙纤,設(shè)置屬性等
public class QQStepView extends View {
private int mOuterColor = Color.RED;
private int mInnerColor = Color.BLUE;
private int mBorderWidth = 20;
private int mStepTextSize;
private int mStepTextColor;
private Paint mOuterPaint, mInnerPaint, mTextPaint;
private int mStepMax;//總的步數(shù)
private int mCurrentStep;//當(dāng)前步數(shù)
public QQStepView(Context context) {
this(context, null);
}
public QQStepView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public QQStepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.QQStepView);
mOuterColor = ta.getColor(R.styleable.QQStepView_outerColor, mOuterColor);
mInnerColor = ta.getColor(R.styleable.QQStepView_innerColor, mInnerColor);
mBorderWidth = (int) ta.getDimension(R.styleable.QQStepView_borderWidth, mBorderWidth);
mStepTextSize = ta.getDimensionPixelOffset(R.styleable.QQStepView_stepTextSize, mStepTextSize);
mStepTextColor = ta.getColor(R.styleable.QQStepView_stepTextColor, mStepTextColor);
ta.recycle();
//內(nèi)弧
mOuterPaint = new Paint();
mOuterPaint.setAntiAlias(true);
mOuterPaint.setStrokeWidth(mBorderWidth);
mOuterPaint.setColor(mOuterColor);
mOuterPaint.setStrokeCap(Paint.Cap.ROUND);//設(shè)置下方為圓形
mOuterPaint.setStyle(Paint.Style.STROKE);//設(shè)置內(nèi)部為空心
//外弧
mInnerPaint = new Paint();
mInnerPaint.setAntiAlias(true);
mInnerPaint.setStrokeWidth(mBorderWidth);
mInnerPaint.setColor(mInnerColor);
mInnerPaint.setStrokeCap(Paint.Cap.ROUND);//設(shè)置下方為圓形
mInnerPaint.setStyle(Paint.Style.STROKE);//設(shè)置內(nèi)部為空心
//文字
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(mStepTextSize);
mTextPaint.setColor(mStepTextColor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//調(diào)用者在布局文件中可能 wrap_content導(dǎo)致寬高不一致
//確保是正方形
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width > height ? height : width, width > height ? height : width);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//1.畫外圓弧 邊緣沒有顯示完整
//RectF recf = new RectF(0, 0, getWidth(), getHeight());
int center = getWidth() / 2;
int radius = getWidth() / 2 - mBorderWidth / 2;
//mBorderWidth/2,mBorderWidth/2,getWidth()-mBorderWidth/2,getWidth()-mBorderWidth/2
RectF recf = new RectF(center - radius,
center - radius,
center + radius,
center + radius);
canvas.drawArc(recf, 135, 270, false, mOuterPaint);
//2.繪制內(nèi)圓弧
float sweepAngle = (float) mCurrentStep / mStepMax;
canvas.drawArc(recf, 135, sweepAngle * 270, false, mInnerPaint);
//3.繪制文字
String stepText = mCurrentStep + "";
Rect rect = new Rect();
mTextPaint.getTextBounds(stepText,0,stepText.length(),rect);
int dx = getWidth() / 2 - rect.width() / 2;
//第一種方式獲取高度
//int dy = getWidth() / 2 + rect.width()/2;
//第二種表達(dá)方式獲取高度
Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();
//獲取中心(fontMetrics.bottom - fontMetrics.top) / 2
int dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
int baseLine = getHeight() / 2 + dy;
canvas.drawText(stepText, dx, baseLine, mTextPaint);
}
//其他耗溜,寫幾個(gè)方法讓他動(dòng)起來
public void setStepMax(int mStepMax) {
this.mStepMax = mStepMax;
}
public void setCurrentStep(int mCurrentStep) {
this.mCurrentStep = mCurrentStep;
//不斷繪制 onDraw()
invalidate();
}
}
在MainActivity中設(shè)置動(dòng)畫
final QQStepView qqStepView = (QQStepView) findViewById(R.id.step_view);
qqStepView.setStepMax(5000);
//屬性動(dòng)畫
ValueAnimator animator = ValueAnimator.ofFloat(0, 3000);//0到3000的變化
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentStep = (float) animation.getAnimatedValue();//獲取當(dāng)前值
qqStepView.setCurrentStep((int) currentStep);
}
});
animator.setDuration(2000);
animator.start();