您的位置:首页 > 移动开发 > Android开发

自定义View - 简单的成绩条

2016-10-19 15:36 204 查看
效果图



ScoreView的要求

0-60
60-70
70-80
80-90
90-120
这几段对应不同颜色

处理
padding
,
<0或>120的特殊值
,
match_parent 和 wrap_content


具体步骤

1.在attrs.xml文件中定义属性

<attr name="score" format="integer" />
<attr name="scoreColor" format="color" />
<attr name="baseLineColor" format="color" />
<declare-styleable name="ScoreView">
<attr name="score" />
<attr name="scoreColor" />
<attr name="baseLineColor" />
</declare-styleable>


2.在自定义View中获取这些属性

public ScoreView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.getTheme().
obtainStyledAttributes(attrs, R.styleable.ScoreView, defStyleAttr, 0);
int count = ta.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = ta.getIndex(i);
switch (attr) {
case R.styleable.ScoreView_baseLineColor:
baselineColor = ta.getColor(attr, Color.GRAY);
break;
case R.styleable.ScoreView_scoreColor:
scoreColor = ta.getColor(attr, Color.RED);
break;
case R.styleable.ScoreView_score:
//应该加上 StringToInteger 的检测
mScore = Integer.parseInt(ta.getString(attr));
break;
}
}
ta.recycle();
mScore = Math.min(mScore, 120);
mScore = Math.max(0, mScore);
mScoreFraction = (float) (mScore / 10.0);
paint = new Paint();
}


3.重写onMeasure

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int mWidth = MeasureSpec.getSize(widthMeasureSpec);
int mHeight = MeasureSpec.getSize(heightMeasureSpec);
int mWidthMode = MeasureSpec.getMode(widthMeasureSpec);
int mHeightMode = MeasureSpec.getMode(heightMeasureSpec);

int lineWidth = 0;//基准线的长度
Paint paint = new Paint();
Rect boundScore = new Rect();
paint.setTextSize(30);
paint.getTextBounds("120", 0, "120".length(), boundScore); //所得分数对应的Rect
Rect boundDial = new Rect();
paint.setTextSize(20);
paint.getTextBounds("120", 0, "120".length(), boundDial);//分数刻度对应的Rect

if (mWidthMode == MeasureSpec.EXACTLY) {
width = mWidth;
lineWidth = width - boundScore.width() - getPaddingLeft() - getPaddingRight();
} else {
width = DensityUtils.getScreenWidth(ScoreApplication.getScoreApplicationContext()) / 2;
lineWidth = width - (boundScore.width()) - getPaddingLeft() - getPaddingRight();
}

if (mHeightMode == MeasureSpec.EXACTLY) { //该情况不进行处理,即如果指定具体高度,不可过小
height = mHeight;
} else {
int baseHeight = DensityUtils.getScreenHeight(ScoreApplication.getScoreApplicationContext()) / 5;
int minHeight = Math.max(boundScore.height(), 2 * stepY) + 4 * stepY;
height = Math.min(baseHeight, minHeight);
height += (getPaddingTop() + getPaddingBottom());
}

baseLineWidth = (int) (lineWidth * 0.9);
baseLineStart = (int) (lineWidth * 0.05);
//计算出 刻度线各里程碑对应的x坐标,即DialStonesX[i]的值
for (int i = 0; i < DialStones.length; i++) {
DialStonesX[i] = (int) ((float) (DialStones[i] / 120.0) * baseLineWidth + baseLineStart);
}
setMeasuredDimension(width, height);
}


4.重写onDraw

@Override
protected void onDraw(Canvas canvas) {
paint.setStrokeWidth(mDialWidth);//paint线条宽度
paint.setColor(baselineColor);
paint.setTextSize(20);
//绘制水平基线
canvas.drawLine(baseLineStart, height / 2, baseLineWidth + baseLineStart, height / 2, paint);
int baseX = baseLineStart + baseLineWidth / 2;
int baseY = height / 2;
int stepX = baseLineWidth / 12;
//绘制第一个刻度 0
canvas.drawLine(baseLineStart + mDialWidth / 2, baseY, baseLineStart + mDialWidth / 2, baseY + stepY, paint);
canvas.drawText("0", baseLineStart, baseY + stepY * 3, paint);
//绘制刻度 60 70 80 90 100 120
for (int i = 0; i < 7; i++) {
if (i == 5) continue;
canvas.drawLine(baseX + i * stepX + mDialWidth / 2, baseY, baseX + i * stepX + mDialWidth / 2, baseY + stepY, paint);
canvas.drawText(DialNumbers[i] + "", baseX + i * stepX - stepY, baseY + 3 * stepY, paint);
}
//绘制进度
int destX = (int) (baseLineStart + stepX * mScoreFraction + mDialWidth);
int indexBetweenDialStonesX = getIndexInDialStonesX(destX);
//如果成绩<=60
if (indexBetweenDialStonesX == 0) {
paint.setColor(getResources().getColor(progressRes[0]));
canvas.drawRect(baseLineStart, baseY - stepY * 3, destX, baseY - stepY, paint);
} else {
//除去最后一部分,之前的部分可以通过 刻度里程碑的X坐标确定起止X位置
for (int i = 0; i < indexBetweenDialStonesX; i++) {
paint.setColor(getResources().getColor(progressRes[i]));
if (i == 0) {
canvas.drawRect(baseLineStart, baseY - stepY * 3, DialStonesX[i], baseY - stepY, paint);
} else {
canvas.drawRect(DialStonesX[i - 1], baseY - stepY * 3, DialStonesX[i], baseY - stepY, paint);
}
}
//绘制最后一段,起始点X坐标为对应刻度里程碑的X坐标,终止点坐标为destX
paint.setColor(getResources().getColor(progressRes[indexBetweenDialStonesX]));
canvas.drawRect(DialStonesX[indexBetweenDialStonesX - 1], baseY - stepY * 3, destX, baseY - stepY, paint);
}
//绘制分数
paint.setColor(scoreColor);
paint.setTextSize(30);
paint.setTypeface(Typeface.create(Typeface.DEFAULT_BOLD, Typeface.BOLD));
canvas.drawText("" + mScore, (int) (baseLineStart + stepX * mScoreFraction + stepY), (int) (baseY - stepY * 1.3), paint);
super.onDraw(canvas);
}


根据进度条终点的X坐标,计算对应于第几个刻度里程碑

private int getIndexInDialStonesX(int dest) {
for (int i = DialStonesX.length - 1; i >= 0; i--) {
if (dest > DialStonesX[i] + mDialWidth) return i + 1;
}
return 0;
}


5.支持属性动画

public void setScore(int score) {
mScore = Math.min(score,120);
mScore = Math.max(mScore,0);
mScoreFraction = (float) (mScore / 10.0);
invalidate();
}


6.引用ScoreView并调用属性动画

<org.issme.gh.scoreviewdemo.View.ScoreView
android:id="@+id/acScore_scrollView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
hyzhang:baseLineColor="@color/baseLine"
hyzhang:score="98"
hyzhang:scoreColor="@color/score" />


要加上
xmlns:hyzhang="http://schemas.android.com/apk/res-auto"


在代码使用属性动画

public void setScore(View view) {
int random = new Random().nextInt(61) + 60;
ObjectAnimator.ofInt(scoreView, "Score", random).setDuration(random * 10).start();
}


欢迎指教, Demo下载请戳
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android