当前位置:   article > 正文

Android 自定义带进度显示的半圆形进度条ArcTextProgressBar_progressbar 半圆角

progressbar 半圆角

自定义ArcTextProgressBar

这个控件最终需要实现如下效果:

1、进度条采用半圆弧形式呈现;

2、圆弧上有已完成的进度提示;

见下面效果图:



其他一些诸于设置进度条宽度、颜色,进度文字圆大小等属性具体见代码中的定义,好废话不说,上代码:

首先是自定义的属性,这样便于在xml文件中设置属性:

  1. <declare-styleable name="ArcTextProgressBar">
  2. <attr name="arc_text_progress_stroke_width" format="integer" />
  3. <attr name="arc_text_progress_text_bg_circle_diameter" format="integer" />
  4. <attr name="arc_text_progress_text_string_prefix" format="string" />
  5. <attr name="arc_text_progress_text_string_suffix" format="string" />
  6. <attr name="arc_text_progress_min_progress" format="integer" />
  7. <attr name="arc_text_progress_current_progress" format="integer" />
  8. <attr name="arc_text_progress_max_progress" format="integer" />
  9. <attr name="arc_text_progress_total_arc_color" format="color" />
  10. <attr name="arc_text_progress_current_arc_color" format="color" />
  11. <attr name="arc_text_progress_circle_text_bg_color" format="color" />
  12. <attr name="arc_text_progress_circle_text_color" format="color" />
  13. <attr name="arc_text_progress_circle_text_size" format="integer" />
  14. </declare-styleable>


然后是ArcTextProgressBar.java文件,具体说明见注释,应该比较清楚:

  1. public class ArcTextProgressBar extends View {
  2. private int diameter = 600; // 圆弧直径
  3. private int mStokeWidth = 40; // 进度条宽度
  4. private int mTextBgCircleDiameter = 20; // 进度条圆形背景上的致敬
  5. private String mTextStringPrefix = "已完成"; // 进度提示文字前缀
  6. private int mMinProgress = 0;
  7. private int mCurrentProgress = 25; // 进度条当前进度
  8. private int mMaxProgress = 100;
  9. private String mTextStringSuffix = "%"; // 进度提示文字后缀
  10. private int mTotalArcColor = Color.GRAY;
  11. private int mCurrentArcColor = Color.CYAN;
  12. private int mCircleTextBgColor = Color.CYAN;
  13. private int mCircleTextColor = Color.WHITE;
  14. private int mCircleTextSize = dipToPx(8);
  15. private int mStartAngle = 180; // 进度条开始绘制的弧度
  16. private int mSweepAngle = 90; // 进度条滑过的弧度
  17. private int mTotalAngle = 180; // 进度条总共的弧度
  18. private Point mPointTextBgCircleCenter = null; // 文字背景圆的圆心坐标
  19. private RectF mRectBg = null; // 背景矩形
  20. private Paint mPaintAllArc = null; //
  21. private Paint mPaintCurrentArc = null;
  22. private Paint mPaintCircleBg = null;
  23. private StaticLayout mStaticLayout = null;
  24. private TextPaint mPaintCircleText = null;
  25. public ArcTextProgressBar(Context context) {
  26. super(context, null);
  27. initView();
  28. }
  29. public ArcTextProgressBar(Context context, AttributeSet attrs) {
  30. super(context, attrs, 0);
  31. initView();
  32. initConfig(context, attrs);
  33. }
  34. public ArcTextProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
  35. super(context, attrs, defStyleAttr);
  36. initView();
  37. initConfig(context, attrs);
  38. }
  39. private void initConfig(Context context, AttributeSet attrs) {
  40. TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ArcTextProgressBar);
  41. mStokeWidth = typedArray.getInteger(R.styleable.ArcTextProgressBar_arc_text_progress_stroke_width, 40);
  42. mTextBgCircleDiameter = typedArray.getInteger(R.styleable.ArcTextProgressBar_arc_text_progress_text_bg_circle_diameter, 20);
  43. mTextStringPrefix = typedArray.getString(R.styleable.ArcTextProgressBar_arc_text_progress_text_string_prefix);
  44. mTextStringSuffix = typedArray.getString(R.styleable.ArcTextProgressBar_arc_text_progress_text_string_suffix);
  45. mMinProgress = typedArray.getInteger(R.styleable.ArcTextProgressBar_arc_text_progress_min_progress, 0);
  46. mMaxProgress = typedArray.getInteger(R.styleable.ArcTextProgressBar_arc_text_progress_max_progress, 100);
  47. mCurrentProgress = typedArray.getInteger(R.styleable.ArcTextProgressBar_arc_text_progress_current_progress, 25);
  48. mTotalArcColor = typedArray.getColor(R.styleable.ArcTextProgressBar_arc_text_progress_total_arc_color, Color.GRAY);
  49. mCurrentArcColor = typedArray.getColor(R.styleable.ArcTextProgressBar_arc_text_progress_current_arc_color, Color.CYAN);
  50. mCircleTextBgColor = typedArray.getColor(R.styleable.ArcTextProgressBar_arc_text_progress_circle_text_bg_color, Color.CYAN);
  51. mCircleTextColor = typedArray.getColor(R.styleable.ArcTextProgressBar_arc_text_progress_circle_text_color, Color.WHITE);
  52. mCircleTextSize = typedArray.getInteger(R.styleable.ArcTextProgressBar_arc_text_progress_circle_text_size, dipToPx(8));
  53. // 进行初始化设置
  54. if (null == mTextStringPrefix) {
  55. mTextStringPrefix = "已完成";
  56. }
  57. if (null == mTextStringSuffix) {
  58. mTextStringSuffix = "%";
  59. }
  60. setStokeWidth(mStokeWidth);
  61. setTextBgCircleDiameter(mTextBgCircleDiameter);
  62. setTextStringPrefix(mTextStringPrefix);
  63. setTextStringSuffix(mTextStringSuffix);
  64. setMinProgress(mMinProgress);
  65. setMaxProgress(mMaxProgress);
  66. setCurrentProgress(mCurrentProgress);
  67. setTotalArcColor(mTotalArcColor);
  68. setCurrentArcColor(mCurrentArcColor);
  69. setCircleTextBgColor(mCircleTextBgColor);
  70. setCircleTextColor(mCircleTextColor);
  71. typedArray.recycle();
  72. }
  73. @Override
  74. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  75. int width = Math.max(mTextBgCircleDiameter, mStaticLayout.getWidth()) + 10 + diameter;
  76. int height = Math.max(mTextBgCircleDiameter, mStaticLayout.getWidth()) + 10 + diameter / 2;
  77. setMeasuredDimension(width, height);
  78. }
  79. private void initView() {
  80. diameter = getScreenWidth() * 4 / 5 - getPaddingLeft() - getPaddingRight();
  81. // 绘制文字
  82. mPaintCircleText = new TextPaint();
  83. mPaintCircleText.setColor(mCircleTextColor);
  84. mPaintCircleText.setAntiAlias(true);
  85. mPaintCircleText.setTextSize(mCircleTextSize);
  86. float startChangeLinePos = mPaintCircleText.measureText(mTextStringPrefix);
  87. mStaticLayout = new StaticLayout(mTextStringPrefix + mCurrentProgress + mTextStringSuffix,
  88. mPaintCircleText, (int) startChangeLinePos, Layout.Alignment.ALIGN_CENTER, 1.0f, 1.0f, true);
  89. int maxStroke = mStokeWidth + mTextBgCircleDiameter + mStaticLayout.getWidth();
  90. // 计算当前滑过的弧度
  91. mSweepAngle = (int) (mCurrentProgress * 1.0 / 100 * mTotalAngle);
  92. mRectBg = new RectF();
  93. mRectBg.left = Math.max(mTextBgCircleDiameter, mStaticLayout.getWidth()) / 2 + 10;
  94. mRectBg.top = Math.max(mTextBgCircleDiameter, mStaticLayout.getWidth()) / 2 + 10;
  95. mRectBg.right = Math.max(mTextBgCircleDiameter, mStaticLayout.getWidth()) / 2 + 10 + diameter;
  96. mRectBg.bottom = Math.max(mTextBgCircleDiameter, mStaticLayout.getWidth()) / 2 + 10 + diameter;
  97. // 绘制全部进度圆弧
  98. mPaintAllArc = new Paint();
  99. mPaintAllArc.setAntiAlias(true);
  100. mPaintAllArc.setStyle(Paint.Style.STROKE);
  101. mPaintAllArc.setStrokeWidth(mStokeWidth);
  102. mPaintAllArc.setColor(mTotalArcColor);
  103. mPaintAllArc.setStrokeCap(Paint.Cap.ROUND);
  104. // 当前进度的弧形
  105. mPaintCurrentArc = new Paint();
  106. mPaintCurrentArc.setAntiAlias(true);
  107. mPaintCurrentArc.setStyle(Paint.Style.STROKE);
  108. mPaintCurrentArc.setStrokeCap(Paint.Cap.ROUND);
  109. mPaintCurrentArc.setStrokeWidth(mStokeWidth);
  110. mPaintCurrentArc.setColor(mCurrentArcColor);
  111. // 绘制当前文字圆形背景
  112. mPaintCircleBg = new Paint();
  113. mPaintCircleBg.setAntiAlias(true);
  114. mPaintCircleBg.setStyle(Paint.Style.FILL);
  115. mPaintCircleBg.setColor(mCircleTextBgColor);
  116. }
  117. @Override
  118. protected void onDraw(Canvas canvas) {
  119. super.onDraw(canvas);
  120. // 控件背景
  121. // canvas.drawRect(mRectBg, mPaintRectBg);
  122. // 整个弧
  123. canvas.drawArc(mRectBg, mStartAngle, mTotalAngle, false, mPaintAllArc);
  124. // 当前进度
  125. canvas.drawArc(mRectBg, mStartAngle, mSweepAngle, false, mPaintCurrentArc);
  126. // 得到文字背景圆的圆心
  127. mPointTextBgCircleCenter = calculateTextBgCircleCenter();
  128. if (mCurrentProgress == 0 || mCurrentProgress == 100) {
  129. canvas.drawCircle(mPointTextBgCircleCenter.x, mPointTextBgCircleCenter.y - mStaticLayout.getWidth() / 2,
  130. ((Math.max(mStokeWidth, mTextBgCircleDiameter) + mStaticLayout.getWidth()) / 2), mPaintCircleBg);
  131. //开始绘制文字的位置
  132. canvas.translate(mPointTextBgCircleCenter.x - mStaticLayout.getWidth() / 2,
  133. mPointTextBgCircleCenter.y - mStaticLayout.getHeight());
  134. } else {
  135. canvas.drawCircle(mPointTextBgCircleCenter.x, mPointTextBgCircleCenter.y,
  136. ((Math.max(mStokeWidth, mTextBgCircleDiameter) + mStaticLayout.getWidth()) / 2), mPaintCircleBg);
  137. //开始绘制文字的位置
  138. canvas.translate(mPointTextBgCircleCenter.x - mStaticLayout.getWidth() / 2,
  139. mPointTextBgCircleCenter.y - mStaticLayout.getHeight() / 2);
  140. }
  141. mStaticLayout.draw(canvas);
  142. }
  143. /**
  144. * 关键点:计算文字背景圆的圆心
  145. *
  146. * @return the textBgCircleCenter
  147. */
  148. private Point calculateTextBgCircleCenter() {
  149. // 得到圆环中心圆对应的半径: 外半径 - 内半径 / 2
  150. float arcRadius = mRectBg.width() / 2;
  151. //圆心
  152. Point point = new Point();
  153. point.x = (int) (mRectBg.width() / 2 + mRectBg.left - arcRadius * Math.cos(mSweepAngle * 3.14 / 180));
  154. point.y = (int) (mRectBg.height() / 2 + mRectBg.top - arcRadius * Math.sin(mSweepAngle * 3.14 / 180));
  155. return point;
  156. }
  157. /**
  158. * dip 转换成px
  159. *
  160. * @param dip
  161. * @return
  162. */
  163. private int dipToPx(float dip) {
  164. float density = getContext().getResources().getDisplayMetrics().density;
  165. return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1));
  166. }
  167. /**
  168. * 得到屏幕宽度
  169. *
  170. * @return
  171. */
  172. private int getScreenWidth() {
  173. WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
  174. DisplayMetrics displayMetrics = new DisplayMetrics();
  175. windowManager.getDefaultDisplay().getMetrics(displayMetrics);
  176. return displayMetrics.widthPixels;
  177. }
  178. /**
  179. * 设置progressBar宽度
  180. *
  181. * @param stokeWidth 宽度
  182. */
  183. public void setStokeWidth(int stokeWidth) {
  184. this.mStokeWidth = stokeWidth;
  185. mPaintAllArc.setStrokeWidth(mStokeWidth);
  186. mPaintCurrentArc.setStrokeWidth(mStokeWidth);
  187. invalidate();
  188. }
  189. /**
  190. * 设置progressBar进度提示圆形直径
  191. *
  192. * @param textBgCircleDiameter 直径
  193. **/
  194. public void setTextBgCircleDiameter(int textBgCircleDiameter) {
  195. this.mTextBgCircleDiameter = textBgCircleDiameter;
  196. // todo 根据直径大小来设置里面文字的大小
  197. invalidate();
  198. }
  199. public void setTextStringPrefix(String textStringPrefix) {
  200. this.mTextStringPrefix = textStringPrefix;
  201. invalidate();
  202. }
  203. public void setMinProgress(int minProgress) {
  204. this.mMinProgress = minProgress;
  205. }
  206. public void setCurrentProgress(int currentProgress) {
  207. if (currentProgress < mMinProgress) {
  208. currentProgress = mCurrentProgress;
  209. } else if (currentProgress > mMaxProgress) {
  210. currentProgress = mMaxProgress;
  211. }
  212. this.mCurrentProgress = currentProgress;
  213. mSweepAngle = (int) (mCurrentProgress * 1.0 / 100 * mTotalAngle);
  214. float startChangeLinePos = mPaintCircleText.measureText(mTextStringPrefix);
  215. mStaticLayout = new StaticLayout(mTextStringPrefix + mCurrentProgress + mTextStringSuffix,
  216. mPaintCircleText, (int) startChangeLinePos, Layout.Alignment.ALIGN_CENTER, 1.0f, 1.0f, true);
  217. // todo 设置动画
  218. invalidate();
  219. }
  220. public void setMaxProgress(int maxProgress) {
  221. this.mMaxProgress = maxProgress;
  222. }
  223. public void setTextStringSuffix(String textStringSuffix) {
  224. this.mTextStringSuffix = textStringSuffix;
  225. invalidate();
  226. }
  227. public void setTotalArcColor(int mTotalArcColor) {
  228. this.mTotalArcColor = mTotalArcColor;
  229. mPaintAllArc.setColor(mTotalArcColor);
  230. invalidate();
  231. }
  232. public void setCurrentArcColor(int currentArcColor) {
  233. this.mCurrentArcColor = currentArcColor;
  234. mPaintCurrentArc.setColor(mCurrentArcColor);
  235. invalidate();
  236. }
  237. public void setCircleTextBgColor(int circleTextBgColor) {
  238. this.mCircleTextBgColor = circleTextBgColor;
  239. mPaintCircleBg.setColor(mCircleTextBgColor);
  240. invalidate();
  241. }
  242. public void setCircleTextColor(int circleTextColor) {
  243. this.mCircleTextColor = circleTextColor;
  244. mPaintCircleText.setColor(mCircleTextColor);
  245. invalidate();
  246. }
  247. public void setCircleTextSize(int circleTextSize) {
  248. this.mCircleTextSize = dipToPx(circleTextSize);
  249. mPaintCircleText.setTextSize(mCircleTextSize);
  250. invalidate();
  251. }
  252. }

需要重点注意的问题:

1、进度圆圆心的确定;

2、onMeasure整个空间宽、高的计算;


需要完善的地方:

1、进度圆中的文字大小应该能自适应圆本身的大小;

2、添加进度圆动画效果;

将在之后进行更新。


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/474143
推荐阅读
相关标签
  

闽ICP备14008679号