Android自定义View圆形进度条控件(三)

继续练习自定义View,这次带来的圆形进度条控件与之前的圆形百分比控件大同小异,这次涉及到了渐变渲染以及画布旋转等知识点,效果如下:

虽然步骤类似,但是我还是要写,毕竟基础的东西就是要多练

1、在res/values文件夹下新建attrs.xml文件,编写自定义属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="CircleProgressView">
 <!-- 弧线宽度 -->
 <attr name="arcWidth" format="dimension" />
 <!-- 刻度个数 -->
 <attr name="scaleCount" format="integer" />
 <!-- 渐变起始颜色 -->
 <attr name="startColor" format="color" />
 <!-- 渐变终止颜色 -->
 <attr name="endColor" format="color" />
 <!-- 标签说明文本 -->
 <attr name="labelText" format="string" />
 <!-- 文本颜色 -->
 <attr name="textColor" format="color" />
 <!-- 百分比文本字体大小 -->
 <attr name="progressTextSize" format="dimension" />
 <!-- 标签说明字体大小 -->
 <attr name="labelTextSize" format="dimension" />
 </declare-styleable>
</resources>

2、新建CircleProgressView继承View,重写构造方法:

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

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

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

3、在第三个构造方法中获取自定义属性的值:

 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressView, defStyleAttr, 0);
 mArcWidth = ta.getDimension(R.styleable.CircleProgressView_arcWidth, DensityUtils.dp2px(context, 8));
 mScaleCount = ta.getInteger(R.styleable.CircleProgressView_scaleCount, 24);
 mStartColor = ta.getColor(R.styleable.CircleProgressView_startColor, Color.parseColor("#3FC199"));
 mEndColor = ta.getColor(R.styleable.CircleProgressView_endColor, Color.parseColor("#3294C1"));
 mColorArray = new int[]{mStartColor, mEndColor};
 mLabelText = ta.getString(R.styleable.CircleProgressView_labelText);
 mTextColor = ta.getColor(R.styleable.CircleProgressView_textColor, Color.parseColor("#4F5F6F"));
 mProgressTextSize = ta.getDimension(R.styleable.CircleProgressView_progressTextSize, 160);
 mLabelTextSize = ta.getDimension(R.styleable.CircleProgressView_labelTextSize, 64);
 ta.recycle();

4、创建画图所使用的对象,如Paint、Rect、RectF:

 mArcBackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mArcBackPaint.setStyle(Paint.Style.STROKE);
 mArcBackPaint.setStrokeWidth(mArcWidth);
 mArcBackPaint.setColor(Color.LTGRAY);

 mArcForePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mArcForePaint.setStyle(Paint.Style.STROKE);
 mArcForePaint.setStrokeWidth(mArcWidth);

 mArcRectF = new RectF();

 mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mLinePaint.setStyle(Paint.Style.STROKE);
 mLinePaint.setColor(Color.WHITE);
 mLinePaint.setStrokeWidth(DensityUtils.dp2px(context, 2));

 mProgressTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mProgressTextPaint.setStyle(Paint.Style.FILL);
 mProgressTextPaint.setColor(mTextColor);
 mProgressTextPaint.setTextSize(mProgressTextSize);

 mLabelTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mLabelTextPaint.setStyle(Paint.Style.FILL);
 mLabelTextPaint.setColor(mTextColor);
 mLabelTextPaint.setTextSize(mLabelTextSize);

 mTextRect = new Rect();

5、重写onMeasure()方法,计算自定义View的宽高:

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 setMeasuredDimension(measuredDimension(widthMeasureSpec), measuredDimension(heightMeasureSpec));
 }

 private int measuredDimension(int measureSpec) {
 int result;
 int mode = MeasureSpec.getMode(measureSpec);
 int size = MeasureSpec.getSize(measureSpec);
 if (mode == MeasureSpec.EXACTLY) {
  result = size;
 } else {
  result = 800;
  if (mode == MeasureSpec.AT_MOST) {
  result = Math.min(result, size);
  }
 }
 return result;
 }

6、重写onDraw()方法,绘制圆弧、刻度线和百分比文本、标签说明文本,注意坐标的计算:

 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 mArcRectF.set(mArcWidth / 2, mArcWidth / 2, getWidth() - mArcWidth / 2, getHeight() - mArcWidth / 2);
 //画背景弧线
 canvas.drawArc(mArcRectF, -90, 360, false, mArcBackPaint);
 //设置渐变渲染
 LinearGradient linearGradient = new LinearGradient(getWidth() / 2, 0, getWidth() / 2, getHeight(), mColorArray, null, Shader.TileMode.CLAMP);
 mArcForePaint.setShader(linearGradient);
 //画百分比值弧线
 canvas.drawArc(mArcRectF, -90, mSweepAngle, false, mArcForePaint);
 //画刻度线
 for (int i = 0; i < mScaleCount; i++) {
  canvas.drawLine(getWidth() / 2, 0, getWidth() / 2, mArcWidth, mLinePaint);
  //旋转画布
  canvas.rotate(360 / mScaleCount, getWidth() / 2, getHeight() / 2);
 }
 //画百分比文本
 String progressText = mProgress + "%";
 mProgressTextPaint.getTextBounds(progressText, 0, progressText.length(), mTextRect);
 float progressTextWidth = mTextRect.width();
 float progressTextHeight = mTextRect.height();
 canvas.drawText(progressText, getWidth() / 2 - progressTextWidth / 2,
  getHeight() / 2 + progressTextHeight / 2, mProgressTextPaint);
 //画标签说明文本
 mLabelTextPaint.getTextBounds(mLabelText, 0, mLabelText.length(), mTextRect);
 canvas.drawText(mLabelText, getWidth() / 2 - mTextRect.width() / 2,
  getHeight() / 2 - progressTextHeight / 2 - mTextRect.height(), mLabelTextPaint);
 }

7、暴露一个动态设置百分比的方法:

 public void setProgress(float progress) {
 Log.e("--> ", progress + "");
 ValueAnimator anim = ValueAnimator.ofFloat(mProgress, progress);
 anim.setDuration((long) (Math.abs(mProgress - progress) * 20));
 anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
  mProgress = (float) animation.getAnimatedValue();
  mSweepAngle = mProgress * 360 / 100;
  mProgress = (float) (Math.round(mProgress * 10)) / 10;//四舍五入保留到小数点后两位
  invalidate();
  }
 });
 anim.start();
 }

8、在activity_main.xml布局文件中使用该View:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:cpv="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:paddingBottom="@dimen/activity_vertical_margin"
 android:paddingLeft="@dimen/activity_horizontal_margin"
 android:paddingRight="@dimen/activity_horizontal_margin"
 android:paddingTop="@dimen/activity_vertical_margin"
 tools:context=".MainActivity">

 <com.monkey.circleprogressview.CircleProgressView
 android:id="@+id/circle_progress_view"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_centerInParent="true"
 cpv:arcWidth="8dp"
 cpv:endColor="#126b94"
 cpv:labelText="学习进度"
 cpv:labelTextSize="20sp"
 cpv:progressTextSize="55sp"
 cpv:scaleCount="24"
 cpv:startColor="#12d699"
 cpv:textColor="#4F5F6F" />
</RelativeLayout>

9、在MainActivity中设置监听,传入百分比:

 final CircleProgressView view = (CircleProgressView) findViewById(R.id.circle_progress_view);
 view.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
  float progress = (float) (Math.random() * 100);
  view.setProgress(progress);
 }
 });

代码下载地址:
https://github.com/MonkeyMushroom/CircleProgressView/tree/master

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android 自定义View的使用介绍

    在项目开发中,可能系统自带的一些widget不能满足我们的需求,这时就需要自定义View. 通过查看系统中的常用widget如Button,TextView,EditText,他们都继承自View,所以我们在继承自定义View的时候也自然的需要继承View.1.首先新建一个类LView继承自View 复制代码 代码如下: public class LView extends View { private Paint paint; public LView(Context context) {  

  • Android自定义View设定到FrameLayout布局中实现多组件显示的方法 分享

    如果想在自定义的View上面显示Button 等View组件需要完成如下任务 1.在自定义View的类中覆盖父类的构造(注意是2个参数的) 复制代码 代码如下: public class MyView2 extends View{ public MyView2(Context context,AttributeSet att) {super(context,att); } public void onDraw(Canvas c) { // 这里绘制你要的内容 } } 2.定义布局文件 复制代码

  • Android自定义View绘制的方法及过程(二)

    上一篇<Android 自定义View(一) Paint.Rect.Canvas介绍>讲了最基础的如何自定义一个View,以及View用到的一些工具类.下面讲下View绘制的方法及过程 public class MyView extends View { private String TAG = "--------MyView"; private int width, height; public MyView(Context context, AttributeSet a

  • Android自定义View叶子旋转完整版(六)

    上一篇实现多叶子飘动旋转,今天完成最后的功能. 1.添加右侧旋转枫叶 2.添加滑动条效果,显示百分比 3.修复叶子飘出边框问题 1.添加右侧旋转叶子 Bitmap turnBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.fengshan, null)).getBitmap(); int turnLeafAngle = 0; private void setTurnLeaf(Canvas canvas) { Matrix m

  • Android自定义View简易折线图控件(二)

    继续练习自定义View,这次带来的是简易折线图,支持坐标点点击监听,效果如下: 画坐标轴.画刻度.画点.连线..x.y轴的数据范围是写死的 1 <= x <= 7 ,1 <= y <= 70 ..写活的话涉及到坐标轴刻度的动态计算.坐标点的坐标修改,想想就头大,这里只练习自定义View. 1.在res/values文件夹下新建attrs.xml文件,编写自定义属性: <?xml version="1.0" encoding="utf-8"

  • Android自定义View实现飘动的叶子效果(三)

    上一篇对自定义View及一些方法有所了解,下面做一个简单的叶子飘动的例子 主要技术点 1.添加背景图片canvas.drawBitmap() 2.Matrix动画类 3.Matrix添加到画布上 步骤 1.添加黄色背景颜色 public LeafView(Context context, AttributeSet attrs) { super(context, attrs); bgPaint = new Paint(); bgPaint.setColor(mResources.getColor(

  • Android自定义View实现多片叶子旋转滑动(五)

    上一篇<Android 自定义View(四) 叶子飘动+旋转效果>实现了单片叶子的滑动及旋转,下面实现多片叶子的滑动旋转功能 实现思路比较简单,就是添加一个叶子Leaf类,储存每片叶子的信息, 然后随机产生叶子的坐标及旋转角度,最后实时获取每片叶子信息,添加到画布中 1.Leaf.java 叶子类 private class Leaf { // 叶子的坐标 float x, y; // 旋转角度 int rotateAngle; // 起始时间(ms) long startTime; } 2.

  • Android自定义View中Paint、Rect、Canvas介绍(一)

    自定义View对于新手而言貌似是一个很复杂的东西.格式,各函数的意义.对于大神经常忘记各函数及一些参数的具体写法及意义,刚好在做一个风车效果,把过程及遇到的问题都写下来 1.如何自定义一个View public class LeafView extends View { private String TAG = "--------LeafView"; public LeafView(Context context, AttributeSet attrs) { super(context

  • Android自定义View实现叶子飘动旋转效果(四)

    上一篇实现了叶子飘动功能,<Android自定义叶子飘动> 现在实现旋转效果 要实现这个效果,要在之前的功能上添加2个功能 1.通过matrix.postTranslate(int x, int y)在添加在Y轴上滑动 2.通过matrix.postRotate(float degrees, float px, float py)实现叶子旋转 代码实现 1.获取Y坐标 private float getMatrixY() { float w = (float) ((float) 2 * Mat

  • Android自定义View实现广告信息上下滚动效果

    先看看效果: 实现代码: public class ScrollBanner extends LinearLayout { private TextView mBannerTV1; private TextView mBannerTV2; private Handler handler; private boolean isShow; private int startY1, endY1, startY2, endY2; private Runnable runnable; private Li

随机推荐