拿到美工效果图,咱们程序员就得画得一模一样。 为了不被老板喷,只能多练啊。

    听说你觉得前面几篇都so easy,那今天就带你做个相对比较复杂的。

    转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50468674

    今天的效果图如下(左边是ui图 右边是实现图):

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图1

    自我感觉总体效果还不错,至少大概画得一样了。上一个动态图:

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图2

    其实这个效果实现起来也不是很难,就是计算坐标,弧度之类的可能会比较麻烦,这里分享写这个其中一张手稿,请无视掉很丑的字,其实做自定义view 还是要在纸上多画。所以希望大家也能这么画画,思路会很顺。

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图3

    好的了,废话不多说,快开始。

    首先自定义属性 构造函数,测量什么的 你肯定已经很熟练 直接贴代码了,注释写的很清楚

    1. public class PanelView extends View {
    2. private int mWidth;
    3. private int mHeight;
    4. private int mPercent;
    5. //刻度宽度
    6. private float mTikeWidth;
    7. //第二个弧的宽度
    8. private int mScendArcWidth;
    9. //最小圆的半径
    10. private int mMinCircleRadius;
    11. //文字矩形的宽
    12. private int mRectWidth;
    13. //文字矩形的高
    14. private int mRectHeight;
    15. //文字内容
    16. private String mText = "";
    17. //文字的大小
    18. private int mTextSize;
    19. //设置文字颜色
    20. private int mTextColor;
    21. private int mArcColor;
    22. //小圆和指针颜色
    23. private int mMinCircleColor;
    24. //刻度的个数
    25. private int mTikeCount;
    26. private Context mContext;
    27. public PanelView(Context context) {
    28. this(context, null);
    29. }
    30. public PanelView(Context context, AttributeSet attrs) {
    31. this(context, attrs, 0);
    32. }
    33. public PanelView(Context context, AttributeSet attrs, int defStyleAttr) {
    34. super(context, attrs, defStyleAttr);
    35. mContext = context;
    36. TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.PanelView,defStyleAttr,0);
    37. mArcColor = a.getColor(R.styleable.PanelView_arcColor, Color.parseColor("#5FB1ED"));
    38. mMinCircleColor = a.getColor(R.styleable.PanelView_pointerColor,Color.parseColor("#C9DEEE"));
    39. mTikeCount = a.getInt(R.styleable.PanelView_tikeCount,12);
    40. mTextSize = a.getDimensionPixelSize(PxUtils.spToPx(R.styleable.PanelView_android_textSize,mContext),24);
    41. mText = a.getString(R.styleable.PanelView_android_text);
    42. mScendArcWidth = 50;
    43. }
    44. @Override
    45. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    46. int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    47. int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    48. int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    49. int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    50. if (widthMode == MeasureSpec.EXACTLY) {
    51. mWidth = widthSize;
    52. }else {
    53. mWidth = PxUtils.dpToPx(200,mContext);
    54. }
    55. if (heightMode == MeasureSpec.EXACTLY) {
    56. mHeight = heightSize;
    57. }else {
    58. mHeight = PxUtils.dpToPx(200,mContext);
    59. }
    60. Log.e("wing",mWidth+"");
    61. setMeasuredDimension(mWidth, mHeight);
    62. }

    自定义属性attr.xml

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <resources>
    3. <declare-styleable name="PanelView">
    4. <attr name="arcColor" format="color"/>
    5. <attr name="arcWidth" format="dimension"/>
    6. <attr name="android:text"/>
    7. <attr name="tikeCount" format="integer"/>
    8. <attr name="pointerColor" format="color"/>
    9. <attr name="android:textSize"/>
    10. </declare-styleable>
    11. </resources>
    12.  

    之后来重头戏,也就是绘制。就像画画一样,再复杂的view也是一笔一笔画出来的。所以我们把这个view分解。

    大概分解成如下:1.最外面的弧 2.里面的粗弧 3.中间小圆 4.最小的圆 5.刻度 6.指针 7.矩形 8.文字

    相信让你分开画一定难不倒你。那组合在一起 就是这个view啦。下面开始我们的ondraw()

    按照这个分解来:

    1.绘制最外面的弧 这里需要注意的一点是,如果想让这个圆在view里 记得减去画笔宽度的一半 因为半径是从圆心到画笔宽度的中间算的,所以这里画弧的矩形是 new RectF(strokeWidth, strokeWidth, mWidth - strokeWidth, mHeight - strokeWidth)

    1. Paint p = new Paint();
    2. int strokeWidth = 3;
    3. p.setStrokeWidth(strokeWidth);
    4. p.setAntiAlias(true);
    5. p.setStyle(Paint.Style.STROKE);
    6. p.setColor(mArcColor);
    7. //最外面线条
    8. canvas.drawArc(new RectF(strokeWidth, strokeWidth, mWidth - strokeWidth, mHeight - strokeWidth), 145, 250, false, p);
    9.  

    画出来是这样的效果。

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图4

    2.绘制里面的粗弧,这里比较麻烦的就是需要分为四段,看图:

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图5

    因为大圆和里面粗弧的长短不一致,这里使用百分比来计算 所以会造成指针偏差,那么这里把 1、2两个部分固定来画,然后是3 充满的部分,用百分比来计算需要画多少度,最后是4 空白的部分。

    首先把粗弧的矩形画出来,这里固定了比大弧半径少50(这里其实可以改进,你可以改成动态的让他更灵活),然后计算出百分比。

    1. RectF secondRectF = new RectF(strokeWidth + 50, strokeWidth + 50, mWidth - strokeWidth - 50, mHeight - strokeWidth - 50);
    2. float secondRectWidth = mWidth - strokeWidth - 50 - (strokeWidth + 50);
    3. float secondRectHeight = mHeight - strokeWidth - 50 - (strokeWidth + 50);
    4. float percent = mPercent / 100f;

    接下来绘制1弧,先算出fill充满部分的度数,因为是突出的,所以如果百分比为0,突出左端为白色 如果不为零,则和充满颜色统一。

    1. //充满的圆弧的度数 -5是大小弧的偏差
    2. float fill = 250 * percent ;
    3. //空的圆弧的度数
    4. float empty = 250 - fill;
    5. // Log.e("wing", fill + "");
    6. if(percent==0){
    7. p.setColor(Color.WHITE);
    8. }
    9. //画粗弧突出部分左端
    10. canvas.drawArc(secondRectF,135,11,false,p);

    然后绘制2弧 也就是fill充满的弧,

    1. canvas.drawArc(secondRectF, 145, fill, false, p);

    接下来是3弧,也就是empty未充满的弧,是白色的

    1. p.setColor(Color.WHITE);
    2. //画弧胡的未充满部分
    3. canvas.drawArc(secondRectF, 145 + fill, empty, false, p);

    最后,画出右边突出的4弧, 如果百分比为100 那么和充满的颜色一致,否则为白色

    1. //画粗弧突出部分右端
    2. if(percent == 1){
    3. p.setColor(mArcColor);
    4. }
    5. canvas.drawArc(secondRectF,144+fill+empty,10,false,p);

    这样粗弧也就画完了 来看看效果,就画了两条弧线(实际是5条),就成型了。

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图6

    3.中间的小圆外圈,他的圆心不用多说 是整个view的中心

    1. p.setColor(mArcColor);
    2. //绘制小圆外圈
    3. p.setStrokeWidth(3);
    4. canvas.drawCircle(mWidth / 2, mHeight / 2, 30, p);

    4.绘制内圆,圆心一样的,半径和画笔粗度改变一下

    1. //绘制小圆内圈
    2. p.setColor(mMinCircleColor);
    3. p.setStrokeWidth(8);
    4. mMinCircleRadius = 15;
    5. canvas.drawCircle(mWidth / 2, mHeight / 2, mMinCircleRadius, p);
    6.  

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图7

    5.刻度 刻度处理起来可能比较麻烦,用三角函数算坐标啊 循环画出来。。 这里提供一种比较简单的方法:旋转画布。

    首先引入一个概念,什么叫旋转画布呢,就是把你的画布旋转。。经过测试,旋转以后,整个坐标轴都会对应旋转,一张图举例说明下。

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图8

    大概就是这个意思,画布旋转之后 坐标系也就旋转了,但是原来的图像还在,所以说你比如这个点 x,y旋转前在这个位置, 那么旋转后就是另外一个位置了,但是他们的坐标是相同的。 所以刻度也可以考这种方法画。我们只要画出最顶端的刻度 然后旋转就可以了。

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图9

    绘制第一段刻度, 然后总共是250的弧度 计算出每个刻度的度数 用250除以刻度数mTikeCount,就是每次旋转的度数。接下来把画布逐步旋转,按照原坐标绘制,即可绘制出右半部分刻度。 注意:为了让之后的绘制正常,务必把画布转回原来的位置

    1. //绘制刻度!
    2. p.setColor(mArcColor);
    3. //绘制第一条最上面的刻度
    4. mTikeWidth = 20;
    5. p.setStrokeWidth(3);
    6. canvas.drawLine(mWidth / 2, 0, mWidth / 2, mTikeWidth, p);
    7. //旋转的角度
    8. float rAngle = 250f / mTikeCount;
    9. //通过旋转画布 绘制右面的刻度
    10. for (int i = 0; i < mTikeCount / 2; i++) {
    11. canvas.rotate(rAngle, mWidth / 2, mHeight / 2);
    12. canvas.drawLine(mWidth / 2, 0, mWidth / 2, mTikeWidth, p);
    13. }
    14. //现在需要将将画布旋转回来
    15. canvas.rotate(-rAngle * mTikeCount / 2, mWidth / 2, mHeight / 2);

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图10

    左半部分同理,需要改变的度数为负 就好了

    1. //通过旋转画布 绘制左面的刻度
    2. for (int i = 0; i < mTikeCount / 2; i++) {
    3. canvas.rotate(-rAngle, mWidth / 2, mHeight / 2);
    4. canvas.drawLine(mWidth / 2, 0, mWidth / 2, mTikeWidth, p);
    5. }
    6. //现在需要将将画布旋转回来
    7. canvas.rotate(rAngle * mTikeCount / 2, mWidth / 2, mHeight / 2);
    8.  

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图11

    6.指针 指针的绘制和刻度相似,先算出来百分比所占的度数 然后根据 是否大于50%来旋转画布。

    指针的起终点是 总view高度的一半 粗弧矩形的一半 加上小圆,前面坐标讲解了那么,这个也一样,自己拿起笔算一算。

    注意这里画布旋转我通过计算得出一个公式 250 * percent - 250/2。

    如果小于50% 则为负 如果大于50%则为正,然后进行旋转。

    切忌最后一定要将画布转回来。

    1. //绘制指针
    2. p.setColor(mMinCircleColor);
    3. p.setStrokeWidth(4);
    4. //按照百分比绘制刻度
    5. canvas.rotate(( 250 * percent - 250/2), mWidth / 2, mHeight / 2);
    6. canvas.drawLine(mWidth / 2, (mHeight / 2 - secondRectHeight / 2) + mScendArcWidth / 2 + 2, mWidth / 2, mHeight / 2 - mMinCircleRadius, p);
    7. //将画布旋转回来
    8. canvas.rotate(-( 250 * percent - 250/2), mWidth / 2, mHeight / 2);
    9.  

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图12

    接下来就是画矩形和文字。没什么好说的了,坐标也是X周围mWidth/2 y轴自己根据圆心微调一个距离

    1. //绘制矩形
    2. p.setStyle(Paint.Style.FILL);
    3. p.setColor(mArcColor);
    4. mRectWidth = 60;
    5. mRectHeight = 25;
    6. //文字矩形的最底部坐标
    7. float rectBottomY = mHeight/2 + secondRectHeight/3+mRectHeight;
    8. canvas.drawRect(mWidth/2-mRectWidth/2,mHeight/2 + secondRectHeight/3,mWidth/2+mRectWidth/2,rectBottomY,p);
    9. p.setTextSize(mTextSize);
    10. mTextColor = Color.WHITE;
    11. p.setColor(mTextColor);
    12. float txtLength = p.measureText(mText);
    13. canvas.drawText(mText,(mWidth-txtLength)/2,rectBottomY + 40,p);
    14. super.onDraw(canvas);

    这样完成了整个view的绘制。

    手把手带你画一个 时尚仪表盘 Android 自定义View - 图13

    下面要做的就是为了方便使用者,提供一些设置属性的方法。

    1. /**
    2. * 设置百分比
    3. * @param percent
    4. */
    5. public void setPercent(int percent) {
    6. mPercent = percent;
    7. invalidate();
    8. }
    9. /**
    10. * 设置文字
    11. * @param text
    12. */
    13. public void setText(String text){
    14. mText = text;
    15. invalidate();
    16. }
    17. /**
    18. * 设置圆弧颜色
    19. * @param color
    20. */
    21. public void setArcColor(int color){
    22. mArcColor = color;
    23. invalidate();
    24. }
    25. /**
    26. * 设置指针颜色
    27. * @param color
    28. */
    29. public void setPointerColor(int color){
    30. mMinCircleColor = color;
    31. invalidate();
    32. }
    33. /**
    34. * 设置文字大小
    35. * @param size
    36. */
    37. public void setTextSize(int size){
    38. mTextSize = size;
    39. invalidate();
    40. }
    41. /**
    42. * 设置粗弧的宽度
    43. * @param width
    44. */
    45. public void setArcWidth(int width){
    46. mScendArcWidth = width;
    47. invalidate();
    48. }

    大功告成!!!一个看似复杂的view 经过我们一步一步绘制遍完成了。

    其实技术的养成也是这样,只要一步一步脚踏实地的去练习,我相信总有一天我能成为大神。

    本项目地址 :PanelView 求关注 求评论 求star!!!!!!