自定义View - 简单的成绩条

效果图
这里写图片描述

ScoreView的要求
  • 0-6060-7070-8080-9090-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下载请戳

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值