• 自定义控件——视图的构建过程——视图的绘制方法


    视图绘制有两种方法,分别是onDraw和dispatchDraw,它们的区别主要有下列两点:

    (1)onDraw既可用于普通控件,也可用于布局类视图;而dispatchDraw专门用于布局类视图,像线性布局LinearLayout、相对布局RelativeLayout都属于布局类视图。

    (2)onDraw方法先执行,dispatchDraw方法后执行,这两个方法中间再执行下级视图的绘制方法。

    xml布局:

    1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    2. android:layout_width="match_parent"
    3. android:layout_height="match_parent"
    4. android:orientation="vertical"
    5. android:padding="5dp" >
    6. <RelativeLayout
    7. android:layout_width="match_parent"
    8. android:layout_height="40dp" >
    9. <TextView
    10. android:id="@+id/tv_draw"
    11. android:layout_width="wrap_content"
    12. android:layout_height="match_parent"
    13. android:layout_alignParentLeft="true"
    14. android:gravity="center"
    15. android:text="绘图方式:"
    16. android:textColor="@color/black"
    17. android:textSize="17sp" />
    18. <Spinner
    19. android:id="@+id/sp_draw"
    20. android:layout_width="match_parent"
    21. android:layout_height="match_parent"
    22. android:layout_toRightOf="@+id/tv_draw"
    23. android:gravity="left|center"
    24. android:spinnerMode="dialog" />
    25. </RelativeLayout>
    26. <!-- 自定义的绘画视图,需要使用全路径 -->
    27. <com.example.myapplication.widget.DrawRelativeLayout
    28. android:id="@+id/drl_content"
    29. android:layout_width="match_parent"
    30. android:layout_height="150dp">
    31. <Button
    32. android:id="@+id/btn_center"
    33. android:layout_width="wrap_content"
    34. android:layout_height="wrap_content"
    35. android:layout_centerHorizontal="true"
    36. android:padding="10dp"
    37. android:text="我在中间"
    38. android:textColor="@color/black"
    39. android:textSize="20sp"
    40. android:visibility="gone" />
    41. </com.example.myapplication.widget.DrawRelativeLayout>
    42. </LinearLayout>

    代码:

    1. package com.example.myapplication;
    2. import androidx.appcompat.app.AppCompatActivity;
    3. import android.os.Bundle;
    4. import android.view.View;
    5. import android.widget.AdapterView;
    6. import android.widget.ArrayAdapter;
    7. import android.widget.Button;
    8. import android.widget.Spinner;
    9. import com.example.myapplication.widget.DrawRelativeLayout;
    10. public class MainActivity extends AppCompatActivity
    11. {
    12. private DrawRelativeLayout drl_content; // 声明一个绘画布局对象
    13. private Button btn_center;
    14. @Override
    15. protected void onCreate(Bundle savedInstanceState)
    16. {
    17. super.onCreate(savedInstanceState);
    18. setContentView(R.layout.activity_main);
    19. // 从布局文件中获取名叫drl_content的绘画布局
    20. drl_content = findViewById(R.id.drl_content);
    21. btn_center = findViewById(R.id.btn_center);
    22. initTypeSpinner(); // 初始化绘图方式的下拉框
    23. }
    24. // 初始化绘图方式的下拉框
    25. private void initTypeSpinner()
    26. {
    27. ArrayAdapter<String> drawAdapter = new ArrayAdapter<String>(this, R.layout.item_select, descArray);
    28. Spinner sp_draw = findViewById(R.id.sp_draw);
    29. sp_draw.setPrompt("请选择绘图方式");
    30. sp_draw.setAdapter(drawAdapter);
    31. sp_draw.setOnItemSelectedListener(new DrawSelectedListener());
    32. sp_draw.setSelection(0);
    33. }
    34. private String[] descArray = {"不画图", "画矩形", "画圆角矩形", "画圆圈", "画椭圆", "onDraw画叉叉", "dispatchDraw画叉叉"};
    35. private int[] typeArray = {0, 1, 2, 3, 4, 5, 6};
    36. class DrawSelectedListener implements AdapterView.OnItemSelectedListener
    37. {
    38. public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3)
    39. {
    40. int type = typeArray[arg2];
    41. if (type == 5 || type == 6)
    42. {
    43. btn_center.setVisibility(View.VISIBLE);
    44. }
    45. else
    46. {
    47. btn_center.setVisibility(View.GONE);
    48. }
    49. drl_content.setDrawType(type); // 设置绘图布局的绘制类型
    50. }
    51. public void onNothingSelected(AdapterView<?> arg0) {}
    52. }
    53. }

     

    DrawRelativeLayout
    
    1. package com.example.myapplication.widget;
    2. import android.content.Context;
    3. import android.graphics.Canvas;
    4. import android.graphics.Color;
    5. import android.graphics.Paint;
    6. import android.graphics.Paint.Style;
    7. import android.graphics.Rect;
    8. import android.graphics.RectF;
    9. import android.util.AttributeSet;
    10. import android.widget.RelativeLayout;
    11. public class DrawRelativeLayout extends RelativeLayout
    12. {
    13. private int mDrawType = 0; // 绘制类型
    14. private Paint mPaint = new Paint(); // 创建一个画笔对象
    15. private int mStrokeWidth = 3; // 线宽
    16. public DrawRelativeLayout(Context context)
    17. {
    18. this(context, null);
    19. }
    20. public DrawRelativeLayout(Context context, AttributeSet attrs)
    21. {
    22. super(context, attrs);
    23. mPaint.setAntiAlias(true); // 设置画笔为无锯齿
    24. mPaint.setDither(true); // 设置画笔为防抖动
    25. mPaint.setColor(Color.BLACK); // 设置画笔的颜色
    26. mPaint.setStrokeWidth(mStrokeWidth); // 设置画笔的线宽
    27. mPaint.setStyle(Style.STROKE); // 设置画笔的类型。STROKE表示空心,FILL表示实心
    28. }
    29. // onDraw方法在绘制下级视图之前调用
    30. @Override
    31. protected void onDraw(Canvas canvas)
    32. {
    33. super.onDraw(canvas);
    34. int width = getMeasuredWidth(); // 获得布局的实际宽度
    35. int height = getMeasuredHeight(); // 获得布局的实际高度
    36. if (width > 0 && height > 0) {
    37. if (mDrawType == 1) { // 绘制矩形
    38. Rect rect = new Rect(0, 0, width, height);
    39. canvas.drawRect(rect, mPaint); // 在画布上绘制矩形
    40. } else if (mDrawType == 2) { // 绘制圆角矩形
    41. RectF rectF = new RectF(0, 0, width, height);
    42. canvas.drawRoundRect(rectF, 30, 30, mPaint); // 在画布上绘制圆角矩形
    43. } else if (mDrawType == 3) { // 绘制圆圈
    44. int radius = Math.min(width, height) / 2 - mStrokeWidth;
    45. canvas.drawCircle(width / 2, height / 2, radius, mPaint); // 在画布上绘制圆圈
    46. } else if (mDrawType == 4) { // 绘制椭圆
    47. RectF oval = new RectF(0, 0, width, height);
    48. canvas.drawOval(oval, mPaint); // 在画布上绘制椭圆
    49. } else if (mDrawType == 5) { // 绘制矩形及其对角线
    50. Rect rect = new Rect(0, 0, width, height);
    51. canvas.drawRect(rect, mPaint); // 绘制矩形
    52. canvas.drawLine(0, 0, width, height, mPaint); // 绘制左上角到右下角的线段
    53. canvas.drawLine(0, height, width, 0, mPaint); // 绘制左下角到右上角的线段
    54. }
    55. }
    56. }
    57. // dispatchDraw方法在绘制下级视图之前调用
    58. @Override
    59. protected void dispatchDraw(Canvas canvas)
    60. {
    61. super.dispatchDraw(canvas);
    62. int width = getMeasuredWidth(); // 获得布局的实际宽度
    63. int height = getMeasuredHeight(); // 获得布局的实际高度
    64. if (width > 0 && height > 0)
    65. {
    66. if (mDrawType == 6) { // 绘制矩形及其对角线
    67. Rect rect = new Rect(0, 0, width, height);
    68. canvas.drawRect(rect, mPaint); // 绘制矩形
    69. canvas.drawLine(0, 0, width, height, mPaint); // 绘制左上角到右下角的线段
    70. canvas.drawLine(0, height, width, 0, mPaint); // 绘制左下角到右上角的线段
    71. }
    72. }
    73. }
    74. // 设置绘制类型
    75. public void setDrawType(int type)
    76. {
    77. setBackgroundColor(Color.WHITE); // 背景置为白色,目的是把画布擦干净
    78. mDrawType = type;
    79. invalidate(); // 立即重新绘图,此时会触发onDraw方法和dispatchDraw方法
    80. }
    81. }

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    【Spring boot 使用其他 json 转换框架】
    LeetCode 428. Serialize and Deserialize N-ary Tree【树,BFS,DFS】困难
    【PyTorch】nn.Conv2d函数详解
    【Koltin Flow(四)】Flow背压
    (个人笔记)EDEM耦合Recurdyn流程
    mysql-通过binlog日志复制主从同步
    [附源码]Python计算机毕业设计SSM家居购物系统(程序+LW)
    小程序引入vant-Weapp保姆级教程及安装过程的问题解决
    我们该如何看待加密VC青睐的那些NFT项目?
    【数理方程】定解问题
  • 原文地址:https://blog.csdn.net/m0_61442607/article/details/126678751