首页 > 代码库 > Android 自定义View——动态进度条

Android 自定义View——动态进度条

效果图:

技术分享

这个是看了梁肖的demo,根据他的思路自己写了一个,但是我写的这个貌似计算还是有些问题,从上面的图就可以看出来,左侧、顶部、右侧的线会有被截掉的部分,有懂得希望能给说一下,改进一下,这个过程还是有点曲折的,不过还是觉得收获挺多的。比如通动画来进行动态的展示(之前做的都是通过Handler进行更新的所以现在换一种思路觉得特别好),还有圆弧的起止角度,矩形区域的计算等!关于绘制我们可以循序渐进,比如最开始先画圆,然后再画周围的线,最后设置动画部分就可以了。不多说了,上代码了。

代码

自定义View

public class ColorProgressBar extends View{
    //下面这两行在本demo中没什么用,只是前几天看别人的代码时学到的按一定尺寸,设置其他尺寸的方式,自动忽略或者学习一下也不错
//    private int defaultStepIndicatorNum= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,40,getResources().getDisplayMetrics());
//    int mCircleRadius=0.28f*defaultStepIndicatorNum;


    //布局的宽高
    private int mWidth;
    private int mHeight;
    //直径
    private int mDiameter=500;

    //底层圆画笔
    private Paint mPaintbg;
    //顶层圆的画笔
    private Paint mPaintft;
    //周围线的画笔
    private Paint mPaintLine;

    //外层线条的长度
    private int mLongItem=dip2px(20);
    //线条与圆的间距
    private int mDistanceItem=dip2px(10);
    //进度条的最大宽度(取底层进度条与顶层进度条宽度最大的)
    private int mProgressWidth;

    //底层圆的颜色
    private int mBackColor;
    //顶层圆的颜色
    private int mFrontColor;
    //底层圆、顶层圆的宽度
    private float mBackWidth;
    private float mFrontWidth;
    //设置进度
    private float currentvalue;
    //通过动画演示进度
    private ValueAnimator animator;
    private int curvalue;



    public ColorProgressBar(Context context) {
        this(context,null,0);
    }

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

    public ColorProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.ColorProgressBar);
        mBackColor= ta.getColor(R.styleable.ColorProgressBar_back_color, Color.BLACK);
        mFrontColor=ta.getColor(R.styleable.ColorProgressBar_front_color,mBackColor);
        mBackWidth=ta.getDimension(R.styleable.ColorProgressBar_back_width,dip2px(10));
        mFrontWidth=ta.getDimension(R.styleable.ColorProgressBar_front_width,dip2px(10));
        mProgressWidth=mBackWidth>mFrontWidth?(int)mBackWidth:(int)mFrontWidth;
        //注意释放资源
        ta.recycle();
        init();
    }

    /**
     * 都是画笔初始化
     */
    private void init() {
        mPaintbg=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaintbg.setStrokeWidth(mProgressWidth);
        mPaintbg.setColor(mBackColor);
        mPaintbg.setStrokeCap(Paint.Cap.ROUND);
        mPaintbg.setStyle(Paint.Style.STROKE);

        mPaintft=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaintft.setColor(mFrontColor);
        mPaintft.setStyle(Paint.Style.STROKE);
        mPaintft.setStrokeWidth(mFrontWidth);
        mPaintft.setStrokeCap(Paint.Cap.ROUND);

        mPaintLine=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaintLine.setColor(Color.BLACK);
        mPaintLine.setStrokeWidth(5);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//      宽度=高度=(长指针+指针与圆盘的间距+进度条的粗细+半径)*2
        Log.e("测量数据","LongItem:"+mLongItem+"mDistanceItem:"+mDistanceItem+"mProgressWidth:"+mProgressWidth+"mDiameter:"+mDiameter/2);
        mWidth=(int)2*(mLongItem+mDistanceItem+mProgressWidth*2+mDiameter/2);
        mHeight=(int)2*(mLongItem+mDistanceItem+mProgressWidth*2+mDiameter/2);
        Log.e("自定义View","高度"+mHeight+"宽度"+mWidth);
        setMeasuredDimension(mWidth,mHeight);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制底层圆弧,矩形的具体计算见图片
        canvas.drawArc(new RectF(mProgressWidth/2+mDistanceItem+mLongItem,mProgressWidth/2+mDistanceItem+mLongItem,mWidth-mProgressWidth/2-mDistanceItem-mLongItem,mHeight-mProgressWidth/2-mDistanceItem-mLongItem),0,360,true,mPaintbg);
//        SweepGradient gradient=new SweepGradient();
        //绘制边缘线
        canvas.save();
        canvas.rotate(144,mWidth/2,mHeight/2);
        for(int i=0;i<=30;i++){
            canvas.rotate(-9,mWidth/2,mHeight/2);
            if(i%5==0){
                canvas.drawLine(mWidth/2,5,mWidth/2,mLongItem,mPaintbg);
            }else {
                canvas.drawLine(mWidth/2,25,mWidth/2,mLongItem,mPaintLine);
            }
        }

        canvas.restore();
        //给画笔设置渐变
        SweepGradient sweepGradient=new SweepGradient(mWidth/2,mHeight/2,Color.RED,Color.YELLOW);
        mPaintft.setShader(sweepGradient);
        //绘制顶层圆弧,currentvalue在改变时呈现动态效果
        canvas.drawArc(new RectF(mProgressWidth/2+mDistanceItem+mLongItem,mProgressWidth/2+mDistanceItem+mLongItem,mWidth-mProgressWidth/2-mDistanceItem-mLongItem,mHeight-mProgressWidth/2-mDistanceItem-mLongItem),135,currentvalue,false,mPaintft);
        mPaintft.setTextSize(100);
        mPaintft.setTextAlign(Paint.Align.CENTER);
        //绘制文本
        canvas.drawText(String.format("%.0f",currentvalue),mWidth/2,mHeight/2+50,mPaintft);
        invalidate();
    }

    /**
     * 设置动画
     * @param value
     */
    public void setCurrentValue(float value){
//        currentvalue=http://www.mamicode.com/value;
        animator=ValueAnimator.ofFloat(currentvalue,value);
        animator.setDuration(3000);
        animator.setTarget(currentvalue);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                currentvalue= http://www.mamicode.com/(float) valueAnimator.getAnimatedValue();
                curvalue=http://www.mamicode.com/curvalue/10;
            }
        });
        animator.start();

    }
    private int dip2px(float dip){
        float density=getContext().getResources().getDisplayMetrics().density;
        return (int)(dip*density+0.5f);
    }
}

矩形计算

技术分享

Activity调用

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.colorprogressbar);
        mBtStart1= (Button) findViewById(R.id.bt1);

        bar1= (ColorProgressBar) findViewById(R.id.cp1);

        mBtStart1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                bar1.setCurrentValue(270);
            }
        });

    }

自定义属性

 <declare-styleable name="ColorProgressBar">
       <attr name="back_color" format="color"></attr>
        <attr name="front_color" format="color"></attr>
        <attr name="back_width" format="dimension"></attr>
        <attr name="front_width" format="dimension"></attr>
    </declare-styleable>

布局

注意:为了使用自定义属性需要添加一行代码(AS)

xmlns:app="http://schemas.android.com/apk/res-auto"

布局

 <LinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <Button
            android:id="@+id/bt1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="start1"/>

        <com.demo.demo.networkdemo.colorprogressbar.widget.ColorProgressBar
            android:id="@+id/cp1"
            android:layout_width="232dp"
            android:layout_height="match_parent"
            android:layout_gravity="center_horizontal"
            app:back_color="@color/colorPrimary"
            app:front_color="@color/colorAccent"
            android:background="@mipmap/ic_launcher"/>


    </LinearLayout>
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    Android 自定义View——动态进度条