学习鸿洋大神的博客专辑【Android 自定义控件之起步】后所做的demo。
欢迎讨论、建议和指正错误 (^_^)
code: CustomProgressBar.java
-
优化颜色交换逻辑,使用中间变量
tempColor
-
线程增加
stopThread
停止标识判断,离开页面时关闭线程View
中private boolean stopThread = false; // 绘图线程 new Thread() { public void run() { while (!stopThread) { if (mProgress == 360) {//进度条跑完一圈后交换颜色 mProgress = 0; int tempColor = progressColor; progressColor = backgroundColor; backgroundColor = tempColor; } mProgress++;//加 1 操作放在 mProgress == 360 后面,使百分比可以显示 100% ,再从 0% 开始 postInvalidate();//更新 //速度 try { if (mSpeed > 0) { Thread.sleep(500 / mSpeed); } } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); /** * 关闭线程 */ public void stopThread(boolean stop) { stopThread = stop; }
Activity
中@Override protected void onDestroy() { super.onDestroy(); customProgressBar.stopThread(true); }
-
重写
onMeasure()
方法,支持wrap_content
,并设定控件为正方形@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int mWidth; int specWidthMode = MeasureSpec.getMode(widthMeasureSpec); int specWidthSize = MeasureSpec.getSize(widthMeasureSpec); int desireWidth = getPaddingLeft() + getPaddingRight() + StringUtils.getDip(mContext, DEFAULT_SIZE); switch (specWidthMode) { case MeasureSpec.EXACTLY:// match_parent or 指定尺寸 mWidth = specWidthSize; break; case MeasureSpec.AT_MOST:// wrap_content mWidth = Math.min(desireWidth, specWidthSize); break; case MeasureSpec.UNSPECIFIED: //父控件对子控件不加任何束缚,子元素可以得到任意想要的大小,这种MeasureSpec一般是由父控件自身的特性决定的。 //比如ScrollView,它的子View可以随意设置大小,无论多高,都能滚动显示,这个时候,尺寸就选择自己需要的尺寸size。 default: mWidth = specWidthSize; break; } //正方形,边长以宽为准 setMeasuredDimension(mWidth, mWidth); }
-
修改
onDraw()
绘制方式,将背景条的画圆改为动态画弧,优化画弧有锯齿的问题 -
控件中心增加百分比文字动态更新进度
@Override protected void onDraw(Canvas canvas) { ... //画笔在圆环的中心线上 //画进度条 mPaint.setColor(progressColor); // 设置进度条的颜色 //canvas.drawCircle(centre, centre, radius, mPaint); // 画圆环 canvas.drawArc(oval, -90, mProgress, false, mPaint);//画弧 //画背景条 mPaint.setColor(backgroundColor); // 设置背景条的颜色 //canvas.drawArc(oval, -90, mProgress, false, mPaint); // 根据进度画圆弧 canvas.drawArc(oval, mProgress - 90, 360 - mProgress, false, mPaint);//画弧 //更新百分比数字 String mPercentText = StringUtils.getPercent(mProgress, 360); mTextPaint.getTextBounds(mPercentText, 0, mPercentText.length(), textBound); canvas.drawText(mPercentText, getWidth() / 2 - textBound.width() / 2, getHeight() / 2 + textBound.height() / 2, mTextPaint); }
-
重写
onMeasure()
方法,支持wrap_content
,并设定控件为正方形(见上) -
优化音量加减操作,支持上下滑动手势连续调节音量大小
private float yDown, yMove, delt; private int moveCount; @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: yDown = event.getY(); break; case MotionEvent.ACTION_MOVE://上下滑动动态更改进度条 getParent().requestDisallowInterceptTouchEvent(true);//不让父 view 拦截触摸事件 yMove = event.getY(); delt = yMove - yDown; moveCount = (int) delt / 50; if (moveCount > 0) {//向下滑 for (int i = 0; i < moveCount; i++) { down(); } } else if (moveCount < 0) {//向上滑 for (int i = 0; i < -moveCount; i++) { up(); } } if (Math.abs(moveCount) > 0) { yDown = yMove; } } return true; }
-
增加对音量加减的端点判断
public void up() { if (mCurrentCount < mCount) { mCurrentCount++; postInvalidate(); } } public void down() { if (mCurrentCount > 0) { mCurrentCount--; postInvalidate(); } }
-
增加圆心角属性,可以随意调节为圆环或圆弧
/** * 圆心角度数 */ private int mCentralAangle; /** * 根据参数画出每个进度块 */ private void drawOval(Canvas canvas, int centre, int radius) { RectF oval = new RectF(centre - radius, centre - radius, centre + radius, centre + radius); // 用于定义的圆弧的形状和大小的界限 int mSplitCount = mCount;//分割块的个数,默认为圆形的分割块数,等于mCount /** * 开始画弧的起始角度位置,0 度为 x 轴正方向,顺时针开始画弧 * 此处设置为以 y 轴负方向为起点开始顺时针画弧 */ int startAngle = mSplitSize / 2 + 90; if (mCentralAangle < 360 && mCentralAangle > 0) {//半圆弧 mSplitCount--; startAngle = 270 - mCentralAangle / 2; } else { mCentralAangle = 360; } //根据需要画的个数以及间隙计算每个进度块的长度(以圆周长360为基准) float itemSize = (mCentralAangle * 1.0f - mSplitCount * mSplitSize) / mCount; mPaint.setColor(progressColor); // 画进度条 for (int i = 0; i < mCount; i++) { canvas.drawArc(oval, startAngle + i * (itemSize + mSplitSize), itemSize, false, mPaint); // 根据进度画圆弧 } mPaint.setColor(backgroundColor); // 画进度条背景色 for (int i = 0; i < mCurrentCount; i++) { canvas.drawArc(oval, startAngle + i * (itemSize + mSplitSize), itemSize, false, mPaint); // 根据进度画圆弧 } }
-
控件中心增加百分比文字动态更新进度
onMeasure()
中增加对图片和文字宽度的比较,取最大值。百分比文字代码见上。int desireWidth = getPaddingLeft() + getPaddingRight() + Math.max(mTextBound.width(), mImage.getWidth());// 由图片和文字决定的宽
[Android] (在ScrollView里嵌套view)重叠view里面的onTouchEvent的调用方法
Android自定义View:MeasureSpec的真正意义与View大小控制
感谢以上作者以及部分评论的作者给予的思路和帮助 (^_^)