自定义View

深藏阁楼爱情的钟 2022-07-12 02:40 377阅读 0赞

自定义View步骤

  1. 构造函数 初始化(初始化画笔Paint)
  2. onMeasure 测量View的大小(暂时不用关心)
  3. onSizeChanged 确定View大小(记录当前View的宽高)
  4. onLayout 确定子View布局(无子View,不关心)
  5. onDraw 实际绘制内容(绘制饼状图)
  6. 提供接口 提供接口(提供设置数据的接口)





























































    操作类型 API 备注
    绘制颜色 drawColor, drawRGB, drawARGB 使用单一颜色填充整个画布
    绘制基本形状 drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧
    绘制图片 drawBitmap, drawPicture 绘制位图和图片
    绘制文本 drawText, drawPosText, drawTextOnPath 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字
    绘制路径 drawPath 绘制路径,绘制贝塞尔曲线时也需要用到该函数
    顶点操作 drawVertices, drawBitmapMesh 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用
    画布剪裁 clipPath, clipRect 设置画布的显示区域
    画布快照 save, restore, saveLayerXxx, restoreToCount, getSaveCount 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数
    画布变换 translate, scale, rotate, skew 依次为 位移、缩放、 旋转、错切
    Matrix(矩阵) getMatrix, setMatrix, concat 实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。

示例:

1.自定义扇形图:

通过设置数据名字和数据值自动生成对应的扇形分析图。

cv\_01
主要绘制算法:

  1. if (null == mData)
  2. return;
  3. float currentStartAngle = mStartAngle;
  4. canvas.translate(mWidth/2, mHeight/2);
  5. float r = (float) (Math.min(mHeight,mWidth)/2*0.8);
  6. RectF rect = new RectF(-r,-r,r,r);
  7. for (int i = 0; i< mData.size(); i++){
  8. CircleData data = mData.get(i);
  9. mPaint.setColor(data.getColor());
  10. canvas.drawArc(rect,currentStartAngle,data.getAngle(),true,mPaint);
  11. currentStartAngle += data.getAngle();
  12. // 平移画布
  13. mCenterX = (float) ((float)0.5 * r * Math.cos(Math.toRadians(currentStartAngle - 0.5 * data.getAngle())));
  14. mCenterY = (float) ((float)0.5 * r * Math.sin(Math.toRadians(currentStartAngle - 0.5 * data.getAngle())));
  15. canvas.translate(mCenterX,mCenterY); // 文字中心坐标
  16. // 设置字体颜色
  17. mPaint.setColor(Color.BLACK);
  18. mPaint.setTextSize(30f);
  19. mPaint.setTextAlign(Paint.Align.CENTER);
  20. canvas.drawText(decimalFormat.format(data.getPercentage()*100)+" %",0,0,mPaint);
  21. canvas.translate(-mCenterX,-mCenterY);//绘制文字完成回到原点
  22. }

这里需要特别注意扇形图中文字的绘制,通过获取每一个扇形的夹角以及半径,不断的移动画布,从而来获取文字的绘制位置。
github地址:https://github.com/zoky2017/CustomViewDemo

2.示例2 自定义载入条

cv\_02
此定义View是通过网上的自定义载入条改编而来
从效果上看,我们需要考虑以下几个问题:

1.叶子的随机产生;

2.叶子随着一条正余弦曲线移动;

3.叶子在移动的时候旋转,旋转方向随机,正时针或逆时针;

4.叶子遇到进度条,似乎是融合进入;

5.叶子不能超出最左边的弧角;

7.叶子飘出时的角度不是一致,走的曲线的振幅也有差别,否则太有规律性,缺乏美感;

难点在于载入条的椭圆形的填充及叶子对象飘落轨迹的绘制。

  1. private void drawProgressAndLeafs(Canvas canvas) {
  2. if (mProgress >= TOTAL_PROGRESS) {
  3. mProgress = 0;
  4. }
  5. // mProgressWidth为进度条的宽度,根据当前进度算出进度条的位置
  6. mCurrentProgressPosition = mProgressWidth * mProgress / TOTAL_PROGRESS;
  7. // 即当前位置在图中所示1范围内
  8. if (mCurrentProgressPosition < mArcRadius) {
  9. Log.i(TAG, "mProgress = " + mProgress + "---mCurrentProgressPosition = "
  10. + mCurrentProgressPosition
  11. + "--mArcProgressWidth" + mArcRadius);
  12. // 1.绘制白色ARC,绘制orange ARC
  13. // 2.绘制白色矩形
  14. // 1.绘制白色ARC
  15. canvas.drawArc(mArcRectF, 90, 180, false, mWhitePaint);
  16. // 2.绘制白色矩形
  17. mWhiteRectF.left = mArcRightLocation;
  18. canvas.drawRect(mWhiteRectF, mWhitePaint);
  19. // 绘制叶子
  20. drawLeafs(canvas);
  21. // 3.绘制棕色 ARC
  22. // 单边角度
  23. int angle = (int) Math.toDegrees(Math.acos((mArcRadius - mCurrentProgressPosition)
  24. / (float) mArcRadius));
  25. // 起始的位置
  26. int startAngle = 180 - angle;
  27. // 扫过的角度
  28. int sweepAngle = 2 * angle;
  29. Log.i(TAG, "startAngle = " + startAngle);
  30. canvas.drawArc(mArcRectF, startAngle, sweepAngle, false, mOrangePaint);
  31. } else {
  32. Log.i(TAG, "mProgress = " + mProgress + "---transfer-----mCurrentProgressPosition = "
  33. + mCurrentProgressPosition
  34. + "--mArcProgressWidth" + mArcRadius);
  35. // 1.绘制white RECT
  36. // 2.绘制Orange ARC
  37. // 3.绘制orange RECT
  38. // 这个层级进行绘制能让叶子感觉是融入棕色进度条中
  39. // 1.绘制white RECT
  40. mWhiteRectF.left = mCurrentProgressPosition;
  41. canvas.drawRect(mWhiteRectF, mWhitePaint);
  42. // 绘制叶子
  43. drawLeafs(canvas);
  44. // 2.绘制Orange ARC
  45. canvas.drawArc(mArcRectF, 90, 180, false, mOrangePaint);
  46. // 3.绘制orange RECT
  47. mOrangeRectF.left = mArcRightLocation;
  48. mOrangeRectF.right = mCurrentProgressPosition;
  49. canvas.drawRect(mOrangeRectF, mOrangePaint);
  50. }
  51. }
  52. /**
  53. * 绘制叶子
  54. *
  55. * @param canvas
  56. */
  57. private void drawLeafs(Canvas canvas) {
  58. mLeafRotateTime = mLeafRotateTime <= 0 ? LEAF_ROTATE_TIME : mLeafRotateTime;
  59. long currentTime = System.currentTimeMillis();
  60. for (int i = 0; i < mLeafInfos.size(); i++) {
  61. Leaf leaf = mLeafInfos.get(i);
  62. if (currentTime > leaf.startTime && leaf.startTime != 0) {
  63. // 绘制叶子--根据叶子的类型和当前时间得出叶子的(x,y)
  64. getLeafLocation(leaf, currentTime);
  65. // 根据时间计算旋转角度
  66. canvas.save();
  67. // 通过Matrix控制叶子旋转
  68. Matrix matrix = new Matrix();
  69. float transX = mLeftMargin + leaf.x;
  70. float transY = mLeftMargin + leaf.y;
  71. Log.i(TAG, "left.x = " + leaf.x + "--leaf.y=" + leaf.y);
  72. matrix.postTranslate(transX, transY);
  73. // 通过时间关联旋转角度,则可以直接通过修改LEAF_ROTATE_TIME调节叶子旋转快慢
  74. float rotateFraction = ((currentTime - leaf.startTime) % mLeafRotateTime)
  75. / (float) mLeafRotateTime;
  76. int angle = (int) (rotateFraction * 360);
  77. // 根据叶子旋转方向确定叶子旋转角度
  78. int rotate = leaf.rotateDirection == 0 ? angle + leaf.rotateAngle : -angle
  79. + leaf.rotateAngle;
  80. matrix.postRotate(rotate, transX
  81. + mLeafWidth / 2, transY + mLeafHeight / 2);
  82. canvas.drawBitmap(mLeafBitmap, matrix, mBitmapPaint);
  83. canvas.restore();
  84. } else {
  85. continue;
  86. }
  87. }
  88. }

github地址: https://github.com/zoky2017/CustomViewDemo2

3.挖个坑,后面补上~

发表评论

表情:
评论列表 (有 0 条评论,377人围观)

还没有评论,来说两句吧...

相关阅读

    相关 android定义view

    最近弄的项目中在看到![Image 1][]这种![Center][]加减数量,如是就自己自定义了这样的view。 考虑到图标可能会被替换如是加了个attrs.xml文件,也

    相关 定义View笔记

    这里参考了洪洋大神博客中的许多内容,主要是用于学习自定义View的一个阶段性的总结。 使用自定义View的时候主要有以下的步骤: 1.定义这个View中需要使用到的属性。

    相关 Android定义View

    前几天在郭霖大神的博客上看了自定义View的知识,感觉受益良多,大神毕竟大神。在此总结一下关于Android 自定义View的用法: 首先,自定义View可以由基本控件或者组

    相关 Android定义View

    如何自定义控件 1. 自定义属性的声明和获取 2. 测量onMeasure:测量自定义控件的尺寸 3. 绘制onDraw:绘制自定义控件 4. 状态的存储与恢复: