>>分享Android开发相关的技术 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 19942 个阅读者 刷新本主题
 * 贴子主题:  Android 自定义View实现圆形进度条 深入理解onDraw和onMeasure及自定义属性_移动开发 回复文章 点赞(0)  收藏  
作者:sunshine    发表时间:2020-03-08 23:32:41     消息  查看  搜索  好友  邮件  复制  引用

Android 自定义View实现圆形进度条

深入理解onDraw和onMeasure及自定义属性

Android的View类是用户接口的基础构件,表示屏幕上的一块矩形区域,负责这个区域的绘制和事件处理。自定义View的过程主要包括重写onDraw及onMeasure方法 , 其中onMeasure方法的作用就是计算出自定义View的宽度和高度。这个计算的过程会参照父布局给出的大小(widthMeasureSpec和heightMeasureSpec),以及自己特点算出结果 ;onDraw则根据onMeasure测量后的宽高进行界面的绘制。onDraw主要用到两个类,Canvas和Paint。Canvas画布,相当于现实中画图用的纸或布;Paint画笔,相当于现实中的笔,基本方法有 drawLine 绘制直线 ,drawRect绘制矩形 , drawCirlce绘制圆形。

         自定义圆形进度条效果如下

         点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

         完整代码:                

  package com.circleprogress;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

/**
* Created by Administrator on 2017/6/22.
*/


public   class  CirlceView  extends View {

     //定义第一支画笔,画背景的圆
     private Paint mPaintBackCircle;
     //定义第二支画笔,画前景色的圆(进度条的环)
     private Paint mPaintFrontCircle;

     //定义绘制文字的画笔
     private Paint mPaintText;

     //定义环的宽度
     private  float mStrokeWidth =  50 ;
     private  float mhalfStrokeWidth = mStrokeWidth/ 2;

     //定义圆心坐标和半径
     private  float mX =  200 + mhalfStrokeWidth ;
     private  float mY =  200 + mhalfStrokeWidth ;

     private  float mRadius =  200 ;

     //定义矩形
     private RectF mRectF ;

     //开始进度
     private  int mProgress =  0 ;
     //目标进度
     private  int mTargetProgress =  70 ;
     //最大进度
     private  int mMax =  100 ;

     //定义view的宽高
     private  int mWidth ;
     private  int mHeight ;

     //默认半径
     private  static  final  int DEFAULT_RADIUS =  200 ;
     private  static  final  int DEFAULT_STROKE_WIDTH =  50 ;

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

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

     public  CirlceView(Context context, AttributeSet attrs,  int defStyleAttr) {
         super(context, attrs, defStyleAttr);

         //获取自定义属性
         if( attrs !=  null ){
            TypedArray array  = context.obtainStyledAttributes(attrs , R.styleable.CirlceView);

            mRadius = array.getDimensionPixelSize(R.styleable.CirlceView_radius , DEFAULT_RADIUS);
            mStrokeWidth = array.getDimensionPixelSize(R.styleable.CirlceView_stroke_width,DEFAULT_STROKE_WIDTH);

            array.recycle();
        }
        init();
    }

     private  void  initRect(){

         if(mRectF ==  null ){
            mRectF =  new RectF();
             int viewSize = ( int) (mRadius* 2);

             int left = (mWidth - viewSize)/ 2 ;
             int top = (mHeight - viewSize)/ 2 ;
             int right = left + viewSize ;
             int bottom = top + viewSize ;
            mRectF.set(left,top,right,bottom);
        }
    }

     //初始化画笔
     private  void  init(){
        mPaintBackCircle =  new Paint();
         //设置颜色
        mPaintBackCircle.setColor(Color.WHITE);
         //设置防锯齿
        mPaintBackCircle.setAntiAlias( true);
         //设置为空心
        mPaintBackCircle.setStyle(Paint.Style.STROKE);
        mPaintBackCircle.setStrokeWidth(mStrokeWidth);

        mPaintFrontCircle =  new Paint();
        mPaintFrontCircle.setColor( 0xFF66C796);
        mPaintFrontCircle.setAntiAlias( true);
        mPaintFrontCircle.setStyle(Paint.Style.STROKE);
        mPaintFrontCircle.setStrokeWidth(mStrokeWidth);

        mPaintText =  new Paint();
        mPaintText.setColor( 0xFF66C796);
        mPaintText.setAntiAlias( true);
        mPaintText.setTextSize( 50);
         //设置文字居中
        mPaintText.setTextAlign(Paint.Align.CENTER);
    }

     @Override
     protected  void  onDraw(Canvas canvas) {

        initRect();
         //获取进度百分比
         float angle = mProgress/( float)mMax *  360 ;

        canvas.drawCircle(mWidth/ 2 , mHeight/ 2 , mRadius , mPaintBackCircle );
        canvas.drawArc(mRectF , - 90 , angle ,  false ,mPaintFrontCircle);
        canvas.drawText(mProgress+ "%", mWidth/ 2  , mHeight/ 2 , mPaintText);

         if( mProgress < mTargetProgress) {
             //更新进度
            mProgress +=  2;
             //通知重新绘制
            invalidate();
        }
    }

     @Override
     protected  void  onMeasure( int widthMeasureSpec,  int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);

         //测量宽高
        mWidth = getRealSize(widthMeasureSpec);
        mHeight = getRealSize(heightMeasureSpec);

         //保存测量的宽高
        setMeasuredDimension(mWidth,mHeight);
    }

     //测量View的真实尺寸
     public  int  getRealSize(  int measureSpec ){

         int result = - 1 ;

         int mode = MeasureSpec.getMode(measureSpec);
         int size = MeasureSpec.getSize(measureSpec);

         if( mode == MeasureSpec.AT_MOST || mode == MeasureSpec.UNSPECIFIED){
             //自己计算
            result = ( int) (mRadius *  2 + mStrokeWidth);
        } else {
            result = size ;
        }

         return result;
    }
}

     在values目录下新建attrs.xml文件 , 增加自定义属性        

  <?xml version="1.0" encoding="utf-8"?>
< resources>
< declare-styleable  name= "CirlceView">
     < attr  name= "radius"  format= "dimension"> </ attr>
     < attr  name= "stroke_width"  format= "dimension"> </ attr>
     < attr  name= "back_circle_color"  format= "color"> </ attr>
     < attr  name= "front_arc_color"  format= "color"> </ attr>
     < attr  name= "text_visibility"  format= "boolean"> </ attr>
</ declare-styleable>

</ resources>

     最后在布局文件中引入,设置自定义宽高和半径                

  <?xml version="1.0" encoding="utf-8"?>
< RelativeLayout  xmlns:android= "http://schemas.android.com/apk/res/android"
     xmlns:tools= "http://schemas.android.com/tools"
     xmlns:app= "http://schemas.android.com/apk/res-auto"
     android:id= "@+id/activity_main"
     android:layout_width= "match_parent"
     android:layout_height= "match_parent"
     tools:context= "com.circleprogress.MainActivity">

     < com.circleprogress.CirlceView
         android:layout_width= "match_parent"
         android:layout_height= "match_parent"
         app:radius= "100dp"
         app:stroke_width= "20dp"/>
</ RelativeLayout>

----------------------------
原文链接:https://blog.csdn.net/SakuraMashiro/article/details/73650592

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2020-03-09 22:39:50 重新编辑]
  Java面向对象编程-->数据类型
  JavaWeb开发-->在Web应用中访问Web服务
  JSP与Hibernate开发-->Spring、JPA与Hibernate的整合
  Java网络编程-->客户端协议处理框架
  精通Spring-->Vue指令
  Vue3开发-->Vue Router路由管理器
  如何提高Android代码的安全性
  Android内核开发:图解Android系统的启动过程
  android cts 相关
  Android中的几个布局
  Android那些事儿之LBS定位
  android 自动化测试之MonkeyRunner学习
  Android 使用SQLite数据库
  android 如何监听自身应用被卸载
  Android MapView 定位与Overlay onTap事件处理
  Android数据存储之Content Providers
  Html5调用手机摄像头并实现人脸识别
  Android中shape的使用-Kofi
  Android 代码混淆技术
  Android中使用Activity管理类
  Android adb你真的会用吗?
  更多...
 IPIP: 已设置保密
树形列表:   
1页 2条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。