自定义view之动态圆形进度条
很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项目中能够重用,有时候我们需要自定义其属性,举个很简单的例子,我在项目中的多个界面使用我自定义的View,每个界面该自定义View的颜色都不相同,这时候如果没有自定义属性,那我们是不是需要构建不同颜色的View出来呢,这样子我们的代码就会显得很沉厄,所以这时候我们就需要自定义其属性来满足我们不同的需求,自定义属性呢,我们需要在values下建立attrs.xml文件,在其中定义我们需要定义的属性,然后在自定义View中也要做相对应的修改,我们还是用一个小例子来看看自定义View和自定义属性的使用
今天带大家来自己定义一个带进度的圆形进度条,我们还是先看一下效果吧
1.在values下面新建一个attrs.xml,现在里面定义我们的属性,不同的属性对应不同的format,属性对应的format可以参考http://blog.****.net/pgalxx/article/details/6766677,介绍的还是比较详细,接下来我贴上我在自定义这个进度条所用到的属性
-
<?xml version="1.0" encoding="UTF-8"?> <resources> <!--自定义实现写字板--> <declare-styleable name="CustomPaint"> <attr name="boardBackground" format="color"></attr> <!--写字板背景颜色--> <attr name="paintColor" format="color"></attr><!--画笔颜色--> <attr name="paintWidth" format="dimension"></attr><!--画笔宽度--> </declare-styleable> <!--自定义进度条--> <declare-styleable name="CustomProgress"> <attr name="radius" format="dimension" /><!--半径--> <attr name="strokeWidth" format="dimension" /><!--画笔宽度--> <attr name="circleColor" format="color" /><!--内圆颜色--> <attr name="ringColor" format="color" /><!--进度条颜色--> <attr name="totalProgress" format="integer" /><!--总进度--> <attr name="textColor" format="color|reference" /><!--字体颜色--> <attr name="bigCircleColor" format="color" /><!--外圆颜色--> </declare-styleable> </resources>
2.自定义paint的全部代码贴出来,里面的代码我也有详细的注释
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; /** * @类的用途: * @author: 李晓倩 * @date: 2017/6/11 */ public class CustomPaint extends View { private int mBoardBackground;//写字板背景颜色 private int mPaintColor;//画笔颜色 private int mPaintWidth;//画笔宽度 private Paint mPaint; private Path mPath; public CustomPaint(Context context) { this(context, null); } public CustomPaint(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomPaint(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomPaint); mBoardBackground = typedArray.getColor(R.styleable.CustomPaint_boardBackground, Color.WHITE); mPaintColor = typedArray.getColor(R.styleable.CustomPaint_paintColor, Color.BLACK); mPaintWidth = typedArray.getDimensionPixelSize(R.styleable.CustomPaint_paintWidth, 15); typedArray.recycle(); mPaint = new Paint(); mPath = new Path(); setBackgroundColor(mBoardBackground); mPaint.setColor(mPaintColor); mPaint.setStrokeWidth(mPaintWidth); mPaint.setStyle(Paint.Style.STROKE); mPaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawPath(mPath, mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { float touchX = event.getX(); float touchY = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mPath.moveTo(touchX, touchY); break; case MotionEvent.ACTION_MOVE: mPath.lineTo(touchX, touchY); break; case MotionEvent.ACTION_UP: break; } invalidate(); return true; } }
3.自定义View的全部代码贴出来,里面的代码我也有详细的注释
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; /** * @类的用途: * @author: 李晓倩 * @date: 2017/6/11 */ public class CustomProgress extends View { // 画实心圆的画笔 private Paint mCirclePaint; // 画圆环的画笔 private Paint mRingPaint; // 画字体的画笔 private Paint mTextPaint; // 圆形颜色 private int mCircleColor; // 圆环颜色 private int mRingColor; // 半径 private float mRadius; // 圆环半径 private float mRingRadius; // 圆环宽度 private float mStrokeWidth; // 圆心x坐标 private int mXCenter; // 圆心y坐标 private int mYCenter; // 字的长度 private float mTxtWidth; // 字的高度 private float mTxtHeight; // 总进度 private int mTotalProgress; // 当前进度 private int mProgress; //大圆 private Paint mBigPatient; //字体颜色 private int mTextColor; //外圆颜色 private int mBigCircleColor; public CustomProgress(Context context, AttributeSet attrs) { super(context, attrs); // 获取自定义的属性 initAttrs(context, attrs); initVariable(); } private void initAttrs(Context context, AttributeSet attrs) { TypedArray typeArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomProgress, 0, 0); mRadius = typeArray.getDimension(R.styleable.CustomProgress_radius, 300); mStrokeWidth = typeArray.getDimension(R.styleable.CustomProgress_strokeWidth, 20); mCircleColor = typeArray.getColor(R.styleable.CustomProgress_circleColor, Color.BLUE); mRingColor = typeArray.getColor(R.styleable.CustomProgress_ringColor, Color.RED); mTotalProgress = typeArray.getInt(R.styleable.CustomProgress_totalProgress, 100); mTextColor = typeArray.getColor(R.styleable.CustomProgress_textColor, Color.WHITE); mBigCircleColor = typeArray.getColor(R.styleable.CustomProgress_bigCircleColor, Color.WHITE); typeArray.recycle();//注意这里要释放掉 mRingRadius = mRadius + mStrokeWidth / 2; } private void initVariable() { mCirclePaint = new Paint(); mCirclePaint.setAntiAlias(true); mCirclePaint.setColor(mCircleColor); mCirclePaint.setStrokeCap(Paint.Cap.ROUND); mCirclePaint.setStyle(Paint.Style.FILL); mRingPaint = new Paint(); mRingPaint.setAntiAlias(true); mRingPaint.setColor(mRingColor); mRingPaint.setStrokeCap(Paint.Cap.ROUND); mRingPaint.setStyle(Paint.Style.STROKE); mRingPaint.setStrokeWidth(mStrokeWidth); mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setStyle(Paint.Style.FILL); mTextPaint.setColor(mTextColor); mTextPaint.setTextSize(mRadius / 2); mBigPatient = new Paint(); mBigPatient.setColor(mBigCircleColor); mBigPatient.setAntiAlias(true); mBigPatient.setStyle(Paint.Style.FILL); Paint.FontMetrics fm = mTextPaint.getFontMetrics(); mTxtHeight = (int) Math.ceil(fm.descent - fm.ascent); } @Override protected void onDraw(Canvas canvas) { mXCenter = getWidth() / 2; mYCenter = getHeight() / 2; canvas.drawCircle(mXCenter, mYCenter, mRadius + mStrokeWidth, mBigPatient); canvas.drawCircle(mXCenter, mYCenter, mRadius, mCirclePaint); if (mProgress > 0) { RectF oval = new RectF(); oval.left = (mXCenter - mRingRadius); oval.top = (mYCenter - mRingRadius); oval.right = mRingRadius * 2 + (mXCenter - mRingRadius); oval.bottom = mRingRadius * 2 + (mYCenter - mRingRadius); canvas.drawArc(oval, -90, ((float) mProgress / mTotalProgress) * 360, false, mRingPaint); // String txt = (int) (mProgress * 1.0f / mTotalProgress * 100) + "%"; mTxtWidth = mTextPaint.measureText(txt, 0, txt.length()); canvas.drawText(txt, mXCenter - mTxtWidth / 2, mYCenter + mTxtHeight / 4, mTextPaint); } } public void setProgress(int progress) { mProgress = progress; postInvalidate(); } public void setmTotalProgress(int totalProgress) { mTotalProgress = totalProgress; } }
4.布局文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="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:gravity="center" android:orientation="vertical" tools:context=".MainActivity" > <test.bwie.com.autoviewdemo.CustomProgress android:id="@+id/custom_progress" android:layout_width="100dp" android:layout_height="100dp" app:bigCircleColor="#3de822" app:circleColor="#ffffff" app:radius="30dp" app:strokeWidth="10dp" app:textColor="#000" /> </LinearLayout>
5.使用到自定义view的activity,这里使用的MainActivity
import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private CustomProgress customProgress; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 1) { customProgress.setProgress(msg.arg1); } super.handleMessage(msg); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); customProgress = (CustomProgress) findViewById(R.id.custom_progress); customProgress.setmTotalProgress(100); new Thread(new Runnable() { @Override public void run() { try { for (int i = 1; i <= 100; i++) { Thread.sleep(1000); Message message = handler.obtainMessage(); message.what = 1; message.arg1 = i; handler.sendMessage(message); } } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } }