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


    视图绘制有两种方法,分别是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方法
        }
    }

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    docker学习(3) 容器的启动过程
    docker学习(2) mac中docker-machine使用vmware fusion以及配置国内镜像加速
    docker学习(1) 安装
    maven/gradle 打包后自动上传到nexus仓库
    bash/shell编程学习(3)
    jenkins 入门教程(下)
    jenkins 入门教程(中)
    jenkins 入门教程(上)
    bash/shell编程学习(2)
    ssh远程执行目标机器上的命令
  • 原文地址:https://www.cnblogs.com/xiaobaibailongma/p/16652553.html
Copyright © 2020-2023  润新知