在Android开发中,对于进度条想必大家不会陌生。例如,应用在执行一个耗时操作时,会通过展示一个进度条来显示“加载中...”的动画作为友好页面以提高用户体验。对于这样的进度条,最简单的实现方式就是通过美工给我们切几张不同的图片,最后通过帧动画的方式来实现。通过帧动画实现固然可以,但是对美工的依赖很大。所以今天在这里给大家介绍通过自定义控件来实现一个圆形的进度条。
先看效果图:
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="pointWidth" format="dimension|reference" /> <attr name="circleColor" format="color|reference" /> <attr name="pointColor" format="color|reference" /> <attr name="centerImage" format="reference" /> <declare-styleable name="ProgressView"> <attr name="pointWidth"/> <attr name="circleColor"/> <attr name="pointColor"/> <attr name="centerImage"/> </declare-styleable> </resources>
public ProgressView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); /** * 获得属性 */ TypedArray typedArray = context.getTheme().obtainStyledAttributes( attrs, R.styleable.ProgressView, defStyle, 0); int count = typedArray.getIndexCount(); for (int i = 0; i < count; i++) { int attr = typedArray.getIndex(i); switch (attr) { case R.styleable.ProgressView_pointWidth: mPointWidth = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources() .getDisplayMetrics())); break; case R.styleable.ProgressView_circleColor: mCircleColor = typedArray.getColor(attr, Color.BLACK); break; case R.styleable.ProgressView_pointColor: mPointColor = typedArray.getColor(attr, Color.GREEN); break; case R.styleable.ProgressView_centerImage: mCenterImage = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId(attr, 0)); break; } } typedArray.recycle(); initPaint(); }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mWidth = getWidth(); mHeight = getHeight(); mViewSize = Math.min(mWidth, mHeight) - mPointWidth; // 计算中间圆形大小 int left = (mWidth - mViewSize) / 2; int top = (mHeight - mViewSize) / 2; int right = left + mViewSize; int bottom = top + mViewSize; mRect = new Rect(left, top, right, bottom); mRectf = new RectF(mRect); // 绘制中间图片 drawBitmap(canvas); // 绘制圆环 canvas.drawArc(mRectf, mStartAngle, mDestAngle, false, mCirclePaint); //绘制终点位置圆形 drawCicle(canvas); }
<span style="white-space:pre"> </span>/** * 绘制中间圆形图片 * @param canvas */ private void drawBitmap(Canvas canvas) { // 绘制中间图片 mBitmapShader = new BitmapShader(mCenterImage, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); //计算压缩比例,<span style="font-family: Arial, Helvetica, sans-serif;">让图片能够适应控件的大小</span> int bSize = Math.min(mCenterImage.getWidth(), mCenterImage.getHeight()); float scale = mViewSize * 1.0f / bSize; Matrix matrix = new Matrix(); matrix.setScale(scale, scale); mBitmapShader.setLocalMatrix(matrix); //创建圆形shape,将BitmapShader作为属性设置给shape mShapeDrawable = new ShapeDrawable(new OvalShape()); mShapeDrawable.getPaint().setShader(mBitmapShader); mShapeDrawable.setBounds(mRect); mShapeDrawable.draw(canvas); }
/** * 绘制终点位置圆形 * @param canvas */ private void drawCicle(Canvas canvas) { // 半径 int arcRadius = mViewSize / 2; // 偏转角度 double angle = (double) (mStartAngle + mDestAngle); // 通过三角函数计算终点坐标 float cx = (float) (arcRadius * Math.cos(Math.toRadians(angle))) + mWidth / 2; float cy = (float) (arcRadius * Math.sin(Math.toRadians(angle))) + mHeight / 2; canvas.drawCircle(cx, cy, mPointWidth / 2, mPointPaint); }
/** * 设置进度 */ public void setProgress(double progress){ mProgress = progress; new Thread() { @Override public void run() { try { float totleAngle = (float) (360 * mProgress); for (float angle = 0; angle <= totleAngle; angle += 10) { mDestAngle = angle; postInvalidate(); Thread.sleep(100); } } catch (InterruptedException e) { e.printStackTrace(); } }; }.start(); }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:zk="http://schemas.android.com/apk/res/com.zk.progressdemo" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.zk.progressdemo.MainActivity" > <com.zk.progressdemo.ProgressView android:id="@+id/pv" android:layout_width="500dp" android:layout_height="800dp" android:background="#00FFFF" zk:centerImage="@drawable/center" zk:circleColor="#0000ff" zk:pointColor="#ff0000" zk:pointWidth="20dp" /> </LinearLayout>