自定义数字进度条

先看效果图:

这里写图片描述

酷炫进度条

1.自定义View分析

  1. 自定义属性的声明与获取
  2. 测量onMeasure
  3. 布局onLayout(ViewGroup)
  4. 绘制onDraw
  5. onTouchEvent
  6. onInterceptTouchEvent(ViewGroup)
  7. 状态的恢复和保存

2.自定义属性的声明与获取

2.1分析需要的自定义属性

2.2在res/values/attrs.xml中定义声明

2.3在layout文件中进行使用

2.4在View的构造方法中进行获取

3.代码实现之水平进度条

3.1在values下新建attrs.xml文件,声明如下属性:

<attr name="progress_unreach_color" format="color"></attr>
<attr name="progress_unreach_height" format="dimension"></attr>
<attr name="progress_reach_color" format="color"></attr>
<attr name="progress_reach_height" format="dimension"></attr>
<attr name="progress_text_color" format="color"></attr>
<attr name="progress_text_size" format="dimension"></attr>
<attr name="progress_text_offset" format="dimension"></attr>

<!--使用属性,name是继承自ProgressBar的自定义View的名字-->
<declare-styleable name="NiceHorizontalProgressbarWithProgress">
    <attr name="progress_unreach_color"></attr>
    <attr name="progress_unreach_height"></attr>
    <attr name="progress_reach_color"></attr>
    <attr name="progress_reach_height"></attr>
    <attr name="progress_text_color"></attr>
    <attr name="progress_text_size"></attr>
    <attr name="progress_text_offset"></attr>
</declare-styleable>

3.2代码中获取属性值

public class NiceHorizontalProgressbarWithProgress extends ProgressBar {
//默认的属性设置
private static final int DEFAULT_TEXT_SIZE = 10;//sp
private static final int DEFAULT_TEXT_COLOR = 0xFFC00D1;
private static final int DEFAULT_COLOR_UNREACH = 0xFFD3D6DA;
private static final int DEFAULT_HEIGHT_UNREACH = 2;//dp
private static final int DEFAULT_COLOR_REACH = DEFAULT_TEXT_COLOR;
private static final int DEFAULT_HEIGHT_REACH = 2;//dp
private static final int DEFAULT_TEXT_OFFSET = 10;//dp

//转换数据
private int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
private int mTextColor = DEFAULT_TEXT_COLOR;
private int mUnReachColor = DEFAULT_COLOR_UNREACH;
private int mUnReachHeight = dp2px(DEFAULT_HEIGHT_UNREACH);
private int mReachColor = DEFAULT_COLOR_REACH;
private int mReachHeight = dp2px(DEFAULT_HEIGHT_REACH);
private int mTextOffset = dp2px(DEFAULT_TEXT_OFFSET);

//画笔
private Paint mPaint = new Paint();
private int mReachWidth;

//在代码中new控件时使用这个构造方法
public NiceHorizontalProgressbarWithProgress(Context context) {
    this(context, null);
}

//布局文件中使用控件时使用这个构造方法,2个参数的调用三个参数的构造方法
public NiceHorizontalProgressbarWithProgress(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

//三个参数的构造方法
public NiceHorizontalProgressbarWithProgress(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    //获取自定义的属性
    obtainStyledAttrs(attrs);
}

//获取属性
private void obtainStyledAttrs(AttributeSet attributeSet) {
    TypedArray ta = getContext().obtainStyledAttributes(attributeSet, R.styleable.NiceHorizontalProgressbarWithProgress);

    mTextSize = (int) ta.getDimension(R.styleable.NiceHorizontalProgressbarWithProgress_progress_text_size, mTextSize);
    mTextColor = ta.getColor(R.styleable.NiceHorizontalProgressbarWithProgress_progress_text_color, mTextColor);
    mTextOffset = (int) ta.getDimension(R.styleable.NiceHorizontalProgressbarWithProgress_progress_text_offset, mTextOffset);
    mUnReachColor = ta.getColor(R.styleable.NiceHorizontalProgressbarWithProgress_progress_unreach_color, mUnReachColor);
    mUnReachHeight = (int) ta.getDimension(R.styleable.NiceHorizontalProgressbarWithProgress_progress_unreach_height, mUnReachHeight);
    mReachColor = ta.getColor(R.styleable.NiceHorizontalProgressbarWithProgress_progress_reach_color, mReachColor);
    mReachHeight = (int) ta.getDimension(R.styleable.NiceHorizontalProgressbarWithProgress_progress_reach_height, mReachHeight);

    ta.recycle();
    mPaint.setTextSize(mTextSize);
}

//不同单位的转换方法
private int dp2px(int dpVal) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics());
}

private int sp2px(int spVal) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, getResources().getDisplayMetrics());
}

@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //测量宽度,默认用户会给定
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthVal = MeasureSpec.getSize(widthMeasureSpec);
    //测量高度
    int height = measureHeight(heightMeasureSpec);
    //设定数据
    setMeasuredDimension(widthVal, height);
    //实际绘制的一个区域
    mReachWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
}

//测量高度的方法
private int measureHeight(int heightMeasureSpec) {
    int result = 0;
    int mode = MeasureSpec.getMode(heightMeasureSpec);
    int size = MeasureSpec.getSize(heightMeasureSpec);
    if (mode == MeasureSpec.EXACTLY) {
        //精确测量模式,用户给的精确值
        result = size;
    } else {
        int textHeight = (int) (mPaint.descent() - mPaint.ascent());
        result = getPaddingTop() + getPaddingBottom() + Math.max(Math.max(mReachHeight, mUnReachHeight), Math.abs(textHeight));
        if (mode == MeasureSpec.AT_MOST) {
            //不能超过用户给的最大值
            result = Math.min(result, size);
        }
    }
    return result;
}

@Override
protected synchronized void onDraw(Canvas canvas) {
    //super.onDraw(canvas);
    //自己绘制
    canvas.save();
    canvas.translate(getPaddingLeft(), getHeight() / 2);

    boolean noNeedUnReach = false;

    //draw reachbar
    String text = getProgress() + "%";
    int textWidth = (int) mPaint.measureText(text);

    float radio = getProgress() * 1.0f / getMax();
    float progressX = radio * mReachWidth;
    if (progressX + textWidth > mReachWidth) {
        progressX = mReachWidth - textWidth;
        noNeedUnReach = true;
    }
    float endX = progressX - mTextOffset / 2;
    if (endX > 0) {
        mPaint.setColor(mReachColor);
        mPaint.setStrokeWidth(mReachHeight);
        canvas.drawLine(0, 0, endX, 0, mPaint);
    }
    //draw text
    mPaint.setColor(mTextColor);
    int y = (int) (-(mPaint.descent() + mPaint.ascent()) / 2);
    canvas.drawText(text, progressX, y, mPaint);

    //draw unReachbar
    if (!noNeedUnReach) {
        float startx = progressX + mTextOffset / 2 + textWidth;
        mPaint.setColor(mUnReachColor);
        mPaint.setStrokeWidth(mUnReachHeight);
        canvas.drawLine(startx, 0, mReachWidth, 0, mPaint);
    }
    canvas.restore();
}

}

3.3在布局文件中使用自定义的View(在根部局中加入:xmlns:app=”http://schemas.android.com/apk/res-auto”)

 <com.example.administrator.niceprogressbar.NiceProgressbarWithProgress.NiceHorizontalProgressbarWithProgress
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:id="@+id/pb_01"
        app:progress_reach_color="#ff0000"
        app:progress_text_color="#000fff"
        app:progress_text_size="16sp"
        app:progress_unreach_color="#ffd320"
        app:progress_reach_height="10dp">
    <com.example.administrator.niceprogressbar.NiceProgressbarWithProgress.NiceHorizontalProgressbarWithProgress>

代码实现之圆形进度条(在水平进度条的基础之上)

4.1声明一个半径

<attr name="progress_radius" format="dimension" />
</declare-styleable>

4.2自定义View继承水平进度条,需要把一些private改变成protected

public class RoundProgressbar extends NiceHorizontalProgressbarWithProgress {

//圆的半径
private int mRadius = dp2px(30);
private int mMaxPaintWidth;

public RoundProgressbar(Context context) {
    this(context, null);
}

public RoundProgressbar(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public RoundProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressbar);

    mRadius = (int) ta.getDimension(R.styleable.RoundProgressbar_progress_radius, mRadius);
    ta.recycle();

    mPaint.setStyle(Style.STROKE);
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setStrokeCap(ROUND);
}

@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    mMaxPaintWidth = Math.max(mReachHeight, mUnReachHeight);
    int expect = mRadius * 2 + mMaxPaintWidth + getPaddingLeft() + getPaddingRight();
    int width = resolveSize(expect, widthMeasureSpec);
    int height = resolveSize(expect, heightMeasureSpec);

    int readWidth = Math.max(width, height);

    mRadius = (readWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2;

    setMeasuredDimension(readWidth, readWidth);
}

@Override
protected synchronized void onDraw(Canvas canvas) {
    //super.onDraw(canvas);
    String text = getProgress() + "%";
    float textWidth = mPaint.measureText(text);
    float textHeight=(mPaint.descent()+mPaint.ascent())/2;

    canvas.save();
    canvas.translate(getPaddingLeft()+mMaxPaintWidth/2,getPaddingTop()+mMaxPaintWidth/2);
    mPaint.setStyle(Style.STROKE);
    //draw unReachBar
    mPaint.setColor(mUnReachColor);
    mPaint.setStrokeWidth(mUnReachHeight);
    canvas.drawCircle(mRadius,mRadius,mRadius,mPaint);
    //draw reachBar
    mPaint.setColor(mReachColor);
    mPaint.setStrokeWidth(mReachHeight);
    float sweepAngle = getProgress() * 1.0f / getMax() * 360;
    canvas.drawArc(new RectF(0,0,mRadius*2,mRadius*2),0,sweepAngle,false,mPaint);
    //draw text
    mPaint.setColor(mTextColor);
    mPaint.setStyle(Style.FILL);
    canvas.drawText(text,mRadius-textWidth/2,mRadius-textHeight,mPaint);
    canvas.restore();
}}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值