首页 > 其他分享 >自定义控件——视图的构建过程——视图的绘制方法

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

时间:2022-09-03 14:48:57浏览次数:78  
标签:控件 自定义 width 视图 height mPaint import android 绘制

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

 

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

 

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

xml布局:

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="40dp" >

        <TextView
            android:id="@+id/tv_draw"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="true"
            android:gravity="center"
            android:text="绘图方式:"
            android:textColor="@color/black"
            android:textSize="17sp" />

        <Spinner
            android:id="@+id/sp_draw"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/tv_draw"
            android:gravity="left|center"
            android:spinnerMode="dialog" />
    </RelativeLayout>

    <!-- 自定义的绘画视图,需要使用全路径 -->
    <com.example.myapplication.widget.DrawRelativeLayout
        android:id="@+id/drl_content"
        android:layout_width="match_parent"
        android:layout_height="150dp">

        <Button
            android:id="@+id/btn_center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:padding="10dp"
            android:text="我在中间"
            android:textColor="@color/black"
            android:textSize="20sp"
            android:visibility="gone" />
    </com.example.myapplication.widget.DrawRelativeLayout>

</LinearLayout>

 

 

 

 

 

 

 

 

 

 

代码:

 

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import com.example.myapplication.widget.DrawRelativeLayout;

public class MainActivity extends AppCompatActivity
{

    private DrawRelativeLayout drl_content; // 声明一个绘画布局对象
    private Button btn_center;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        // 从布局文件中获取名叫drl_content的绘画布局
        drl_content = findViewById(R.id.drl_content);
        btn_center = findViewById(R.id.btn_center);

        initTypeSpinner(); // 初始化绘图方式的下拉框
    }

    // 初始化绘图方式的下拉框
    private void initTypeSpinner()
    {
        ArrayAdapter<String> drawAdapter = new ArrayAdapter<String>(this, R.layout.item_select, descArray);

        Spinner sp_draw = findViewById(R.id.sp_draw);

        sp_draw.setPrompt("请选择绘图方式");
        sp_draw.setAdapter(drawAdapter);
        sp_draw.setOnItemSelectedListener(new DrawSelectedListener());
        sp_draw.setSelection(0);
    }

    private String[] descArray = {"不画图", "画矩形", "画圆角矩形", "画圆圈", "画椭圆", "onDraw画叉叉", "dispatchDraw画叉叉"};

    private int[] typeArray = {0, 1, 2, 3, 4, 5, 6};

    class DrawSelectedListener implements AdapterView.OnItemSelectedListener
    {

        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3)
        {
            int type = typeArray[arg2];

            if (type == 5 || type == 6)
            {
                btn_center.setVisibility(View.VISIBLE);
            }
            else
            {
                btn_center.setVisibility(View.GONE);
            }

            drl_content.setDrawType(type); // 设置绘图布局的绘制类型
        }

        public void onNothingSelected(AdapterView<?> arg0) {}
    }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

DrawRelativeLayout

 

 

package com.example.myapplication.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.RelativeLayout;

public class DrawRelativeLayout extends RelativeLayout
{
    private int mDrawType = 0; // 绘制类型

    private Paint mPaint = new Paint(); // 创建一个画笔对象

    private int mStrokeWidth = 3; // 线宽

    public DrawRelativeLayout(Context context)
    {

        this(context, null);
    }

    public DrawRelativeLayout(Context context, AttributeSet attrs)
    {

        super(context, attrs);
        mPaint.setAntiAlias(true); // 设置画笔为无锯齿
        mPaint.setDither(true); // 设置画笔为防抖动
        mPaint.setColor(Color.BLACK); // 设置画笔的颜色
        mPaint.setStrokeWidth(mStrokeWidth); // 设置画笔的线宽
        mPaint.setStyle(Style.STROKE); // 设置画笔的类型。STROKE表示空心,FILL表示实心
    }

    // onDraw方法在绘制下级视图之前调用
    @Override
    protected void onDraw(Canvas canvas)
    {

        super.onDraw(canvas);

        int width = getMeasuredWidth(); // 获得布局的实际宽度
        int height = getMeasuredHeight(); // 获得布局的实际高度

        if (width > 0 && height > 0) {
            if (mDrawType == 1) { // 绘制矩形
                Rect rect = new Rect(0, 0, width, height);
                canvas.drawRect(rect, mPaint); // 在画布上绘制矩形
            } else if (mDrawType == 2) { // 绘制圆角矩形
                RectF rectF = new RectF(0, 0, width, height);
                canvas.drawRoundRect(rectF, 30, 30, mPaint); // 在画布上绘制圆角矩形
            } else if (mDrawType == 3) { // 绘制圆圈
                int radius = Math.min(width, height) / 2 - mStrokeWidth;
                canvas.drawCircle(width / 2, height / 2, radius, mPaint); // 在画布上绘制圆圈
            } else if (mDrawType == 4) { // 绘制椭圆
                RectF oval = new RectF(0, 0, width, height);
                canvas.drawOval(oval, mPaint); // 在画布上绘制椭圆
            } else if (mDrawType == 5) { // 绘制矩形及其对角线
                Rect rect = new Rect(0, 0, width, height);
                canvas.drawRect(rect, mPaint); // 绘制矩形
                canvas.drawLine(0, 0, width, height, mPaint); // 绘制左上角到右下角的线段
                canvas.drawLine(0, height, width, 0, mPaint); // 绘制左下角到右上角的线段
            }
        }
    }

    // dispatchDraw方法在绘制下级视图之前调用
    @Override
    protected void dispatchDraw(Canvas canvas)
    {
        super.dispatchDraw(canvas);

        int width = getMeasuredWidth(); // 获得布局的实际宽度
        int height = getMeasuredHeight(); // 获得布局的实际高度

        if (width > 0 && height > 0)
        {
            if (mDrawType == 6) { // 绘制矩形及其对角线
                Rect rect = new Rect(0, 0, width, height);
                canvas.drawRect(rect, mPaint); // 绘制矩形
                canvas.drawLine(0, 0, width, height, mPaint); // 绘制左上角到右下角的线段
                canvas.drawLine(0, height, width, 0, mPaint); // 绘制左下角到右上角的线段
            }
        }
    }

    // 设置绘制类型
    public void setDrawType(int type)
    {
        setBackgroundColor(Color.WHITE); // 背景置为白色,目的是把画布擦干净

        mDrawType = type;

        invalidate(); // 立即重新绘图,此时会触发onDraw方法和dispatchDraw方法
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

标签:控件,自定义,width,视图,height,mPaint,import,android,绘制
From: https://www.cnblogs.com/xiaobaibailongma/p/16652553.html

相关文章

  • Spring 中使用自定义的 ThreadLocal 存储导致的坑
    Spring中有时候我们需要存储一些和Request相关联的变量,例如用户的登陆有关信息等,它的生命周期和Request相同。一个容易想到的实现办法是使用ThreadLocal:pub......
  • 自定义控件——视图的构建过程——视图的测量方法
              对于wrap_content形式的宽高,App需要测量它们的实际长度,需要测量的实体主要有3种:  (1)文本尺寸测量文本尺寸分为文本的宽度和高度,需根......
  • Google库 来实现 按钮图片等控件的圆角形状 告别shape、各种 drawable
    直接上导入implementation'com.google.android.material:material:1.2.0'MaterialButton继承AppCompatButton,在原来Button的基础上做了一些扩展,如圆角、描边等......
  • MySQL教程 - 视图(View)
    更新记录转载请注明出处。2022年9月3日发布。2022年9月3日从笔记迁移到博客。说明视图是虚拟的表,是一种存储结构可以对视图进行和表一样的操作,但一般用于查询数......
  • Java自定义Annotation注解开发详解
    Java自定义Annotation注解开发详解目录介绍一、运行期的自定义注解1.ClassLevelAnnotation2.MethodLevelAnnotation3.FieldLevelAnnotation4.使用自定义......
  • C#编写折线图控件
    原文:https://blog.csdn.net/bear_csdn/article/details/82918637 C#绘制统计图(柱状图,折线图,扇形图) :https://www.cnblogs.com/ziyiFly/archive/2008/09/24/1297......
  • 视图层与模板层
    网页伪静态伪静态页面其实是动态页面,只是看起来和静态页面一样,将动态网页伪装成静态网页,可以提升网页被搜索引擎收录的概率,表现上网址看的像一个具体的文件路径deftest(......
  • 【Django】 第04回 视图层与模板层
    目录1.网页伪静态2.视图层2.1视图函数的返回值问题2.2视图函数返回json格式数据2.3from表单携带文件数据2.4FEV与CBV2.5CBV源码分析3.模板层3.1模板语法传值3.2......
  • django之视图层与模板层
    一、伪静态网页'''其实就是如果一个网页如果是一个静态网页的话那么浏览器搜索会更容易搜索的到而如果一个动态网页想要让浏览器更容易搜索到的话可以在路由匹配的时......
  • pyqt5控件使用方法
    一)消息框(QMessageBox)一、提供的类型QMessageBox.information信息框QMessageBox.question问答框QMessageBox.warning警告QMessageBox.ctitical危险......