【安卓】自定义View实现画板涂鸦等功能

一、实现效果

画笔测试
开始设计矩形
实现矩形的随笔画
圆形
三角形,还有bug
等腰三角形和塔型
等边三角形
等边三角形计算

二、代码

1、MainActivity.class

package com.lsl.mydrawingboarddemo;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ImageButton;

import com.lsl.mydrawingboarddemo.view.DrawingBoardView;

import java.io.IOException;

/**
 * author lishilin
 * date 2023/8/9
 * desc 负责画板UI交互
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private ImageButton paintBtn,fillPaintBtn,rubberBtn,rectBtn,circleBtn,ellipticBtn,triangleBtn,triangleTowerBtn,selectedBtn,clearBtn,equilateralBtn,rightAngleBtn;
    private ImageButton blackBtn,whiteBtn,redBtn,blueBtn,grayBtn,cyanBtn,currentColorBtn;
    private DrawingBoardView drawingBoardView;
    private View selectColorBoxView;

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

    private void initView(){
        paintBtn = findViewById(R.id.paint);
        fillPaintBtn = findViewById(R.id.fillPaint);
        //rubberBtn = findViewById(R.id.rubber);
        rectBtn = findViewById(R.id.rect);
        circleBtn = findViewById(R.id.circle);
        ellipticBtn = findViewById(R.id.elliptic);
        triangleBtn = findViewById(R.id.triangle);
        triangleTowerBtn = findViewById(R.id.triangleTower);
        clearBtn = findViewById(R.id.clear);
        equilateralBtn = findViewById(R.id.equilateralTriangle);
        drawingBoardView = findViewById(R.id.drawView);
        selectColorBoxView = findViewById(R.id.selectColorBox);
        rightAngleBtn = findViewById(R.id.rightAngle);

        blackBtn = findViewById(R.id.blackBtn);
        whiteBtn = findViewById(R.id.whiteBtn);
        redBtn = findViewById(R.id.redBtn);
        blueBtn = findViewById(R.id.blueBtn);
        grayBtn = findViewById(R.id.grayBtn);
        cyanBtn = findViewById(R.id.cyanBtn);

        paintBtn.setSelected(true);
        selectedBtn = paintBtn;
        blackBtn.setSelected(true);
        currentColorBtn = blackBtn;

        paintBtn.setOnClickListener(this);
        fillPaintBtn.setOnClickListener(this);
        //rubberBtn.setOnClickListener(this);
        rectBtn.setOnClickListener(this);
        circleBtn.setOnClickListener(this);
        ellipticBtn.setOnClickListener(this);
        triangleBtn.setOnClickListener(this);
        triangleTowerBtn.setOnClickListener(this);
        clearBtn.setOnClickListener(this);
        blackBtn.setOnClickListener(this);
        whiteBtn.setOnClickListener(this);
        redBtn.setOnClickListener(this);
        blueBtn.setOnClickListener(this);
        grayBtn.setOnClickListener(this);
        equilateralBtn.setOnClickListener(this);
        rightAngleBtn.setOnClickListener(this);
        cyanBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.paint:
                setSelectBtn(paintBtn);
                drawingBoardView.setPaint("paint");
                selectColorBoxView.setVisibility(View.VISIBLE);
                break;
            case R.id.fillPaint:
                setSelectBtn(fillPaintBtn);
                drawingBoardView.setPaint("fillPaint");
                selectColorBoxView.setVisibility(View.VISIBLE);
                break;
//            case R.id.rubber:
//                setSelectBtn(rubberBtn);
//                drawingBoardView.setEraseMode();
//                selectColorBoxView.setVisibility(View.INVISIBLE);
//                break;
            case R.id.rect:
                setSelectBtn(rectBtn);
                selectColorBoxView.setVisibility(View.VISIBLE);
                drawingBoardView.setPaint("rect");
                break;
            case R.id.circle:
                setSelectBtn(circleBtn);
                selectColorBoxView.setVisibility(View.VISIBLE);
                drawingBoardView.setPaint("drawCircle");
                break;
            case R.id.elliptic:
                setSelectBtn(ellipticBtn);
                selectColorBoxView.setVisibility(View.VISIBLE);
                drawingBoardView.setPaint("drawOval");
                break;
            case R.id.triangle:
                 setSelectBtn(triangleBtn);
                selectColorBoxView.setVisibility(View.VISIBLE);
                 drawingBoardView.setPaint("drawTriangle");
                 break;
            case R.id.equilateralTriangle:
                setSelectBtn(equilateralBtn);
                selectColorBoxView.setVisibility(View.VISIBLE);
                drawingBoardView.setPaint("drawEquilateral");
                break;
            case R.id.triangleTower:
                setSelectBtn(triangleTowerBtn);
                selectColorBoxView.setVisibility(View.VISIBLE);
                drawingBoardView.setPaint("drawTriangleTower");
                break;
            case R.id.rightAngle:
                setSelectBtn(rightAngleBtn);
                selectColorBoxView.setVisibility(View.VISIBLE);
                drawingBoardView.setPaint("drawRightAngle");
                break;
            case R.id.clear:
                clearStyle();//设置点击清除图标时的背景闪烁
                selectColorBoxView.setVisibility(View.VISIBLE);
                if (drawingBoardView!=null){
                    drawingBoardView.clearBoard();
                }
                break;
            case R.id.blackBtn:
                int blackColor = ContextCompat.getColor(this,R.color.black);
                drawingBoardView.setPaintColor(blackColor);
                setCurrentColorBtn(blackBtn);
                break;
            case R.id.blueBtn:
                int blueColor = ContextCompat.getColor(this,R.color.blue);
                drawingBoardView.setPaintColor(blueColor);
                setCurrentColorBtn(blueBtn);
                break;
            case R.id.whiteBtn:
                int whiteColor = ContextCompat.getColor(this,R.color.white);
                drawingBoardView.setPaintColor(whiteColor);
                setCurrentColorBtn(whiteBtn);
                break;
            case R.id.cyanBtn:
                int cyanColor = ContextCompat.getColor(this,R.color.cyan);
                drawingBoardView.setPaintColor(cyanColor);
                setCurrentColorBtn(cyanBtn);
                break;
            case R.id.grayBtn:
                int grayColor = ContextCompat.getColor(this,R.color.gray);
                drawingBoardView.setPaintColor(grayColor);
                setCurrentColorBtn(grayBtn);
                break;
            case R.id.redBtn:
                int redColor = ContextCompat.getColor(this,R.color.red);
                drawingBoardView.setPaintColor(redColor);
                setCurrentColorBtn(redBtn);
                break;
            default:

                break;
        }
    }

    /**
     * 设置选中的图形button
     * @param selectBtn
     */
    private void setSelectBtn(ImageButton selectBtn){
        if (this.selectedBtn!=null){
            this.selectedBtn.setSelected(false);
        }
        selectBtn.setSelected(true);
        this.selectedBtn = selectBtn;
    }

    private void setCurrentColorBtn(ImageButton currentColorBtn){
        if (this.currentColorBtn!=null){
            this.currentColorBtn.setSelected(false);
        }
        currentColorBtn.setSelected(true);
        this.currentColorBtn = currentColorBtn;
    }
    /**
     * 设置点击清除图标时的样式变化,让其背景变色500毫秒
     */
    private void clearStyle(){
        clearBtn.setSelected(true);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                clearBtn.setSelected(false);
            }
        }, 200);
    }

}

2、布局代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/bord_color"
    tools:context=".MainActivity">

    <com.lsl.mydrawingboarddemo.view.DrawingBoardView
        android:id="@+id/drawView"
        android:layout_width="match_parent"
        android:layout_height="650dp"
        android:layout_alignParentTop="true"
        android:background="@color/bord_color" />

    <LinearLayout
        android:layout_width="600dp"
        android:layout_height="80dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/bottom_bg_corner"
        android:gravity="center"
        android:orientation="horizontal">

        <LinearLayout
            android:layout_width="100dp"
            android:layout_height="match_parent"
            android:gravity="center">

            <TableLayout
                android:id="@+id/selectColorBox"
                android:layout_width="40dp"
                android:layout_height="100dp"
                android:gravity="center">

                <TableRow>

                    <ImageButton
                        android:id="@+id/blackBtn"
                        android:background="@drawable/color_select"
                        android:src="@drawable/black" />

                    <ImageButton
                        android:id="@+id/whiteBtn"
                        android:background="@drawable/color_select"
                        android:src="@drawable/white" />
                </TableRow>

                <TableRow>

                    <ImageButton
                        android:id="@+id/redBtn"
                        android:background="@drawable/color_select"
                        android:src="@drawable/red_circle" />

                    <ImageButton
                        android:id="@+id/blueBtn"
                        android:background="@drawable/color_select"
                        android:src="@drawable/blue" />
                </TableRow>

                <TableRow>

                    <ImageButton
                        android:id="@+id/grayBtn"
                        android:background="@drawable/color_select"
                        android:src="@drawable/gray" />

                    <ImageButton
                        android:id="@+id/cyanBtn"
                        android:background="@drawable/color_select"
                        android:src="@drawable/cyan" />
                </TableRow>

            </TableLayout>
        </LinearLayout>

        <TextView
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:background="@color/gray" />

        <LinearLayout
            android:layout_width="500dp"
            android:layout_height="match_parent"
            android:gravity="center">

            <ImageButton
                android:id="@+id/paint"
                android:layout_width="28dp"
                android:layout_height="28dp"
                android:scaleType="centerInside"
                android:layout_marginLeft="8dp"
                android:background="@drawable/shape_selector"
                android:src="@drawable/paint" />

            <ImageButton
                android:id="@+id/fillPaint"
                android:layout_width="32dp"
                android:layout_height="32dp"
                android:scaleType="centerInside"
                android:layout_marginLeft="8dp"
                android:background="@drawable/shape_selector"
                android:src="@drawable/brush" />
<!--            <ImageButton-->
<!--                android:id="@+id/rubber"-->
<!--                android:layout_width="32dp"-->
<!--                android:layout_height="32dp"-->
<!--                android:scaleType="centerInside"-->
<!--                android:layout_marginLeft="8dp"-->
<!--                android:background="@drawable/shape_selector"-->
<!--                android:src="@drawable/rubber" />-->

            <ImageButton
                android:id="@+id/rect"
                android:layout_width="32dp"
                android:layout_height="32dp"
                android:scaleType="centerInside"
                android:layout_marginLeft="8dp"
                android:background="@drawable/shape_selector"
                android:focusable="true"
                android:src="@drawable/rect" />

            <ImageButton
                android:id="@+id/circle"
                android:layout_width="32dp"
                android:layout_height="32dp"
                android:scaleType="centerInside"
                android:layout_marginLeft="8dp"
                android:background="@drawable/shape_selector"
                android:src="@drawable/circle" />

            <ImageButton
                android:id="@+id/elliptic"
                android:layout_width="35dp"
                android:layout_height="35dp"
                android:scaleType="centerInside"
                android:layout_marginLeft="8dp"
                android:background="@drawable/shape_selector"
                android:src="@drawable/elliptic" />

            <ImageButton
                android:id="@+id/triangle"
                android:layout_width="38dp"
                android:layout_height="40dp"
                android:scaleType="centerInside"
                android:layout_marginLeft="8dp"
                android:background="@drawable/shape_selector"
                android:src="@drawable/triangle" />
            <ImageButton
                android:id="@+id/equilateralTriangle"
                android:layout_width="32dp"
                android:layout_height="32dp"
                android:scaleType="centerInside"
                android:layout_marginLeft="8dp"
                android:background="@drawable/shape_selector"
                android:src="@drawable/equilateral_triangle" />
            <ImageButton
                android:id="@+id/rightAngle"
                android:layout_width="37dp"
                android:layout_height="37dp"
                android:scaleType="centerInside"
                android:layout_marginLeft="8dp"
                android:background="@drawable/shape_selector"
                android:src="@drawable/plan" />
            <ImageButton
                android:id="@+id/triangleTower"
                android:layout_width="28dp"
                android:layout_height="28dp"
                android:scaleType="centerInside"
                android:layout_marginLeft="8dp"
                android:background="@drawable/shape_selector"
                android:src="@drawable/tower" />
            <ImageButton
                android:id="@+id/clear"
                android:layout_width="32dp"
                android:layout_height="32dp"
                android:scaleType="centerInside"
                android:layout_marginLeft="8dp"
                android:background="@drawable/shape_selector"
                android:src="@drawable/clear" />
        </LinearLayout>


    </LinearLayout>

</RelativeLayout>

3、自定义View代码

package com.lsl.mydrawingboarddemo.view;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;

import androidx.annotation.Nullable;

import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * author lishilin
 * date 2023/8/9
 * desc 自定义View,实现画板功能
 */
public class DrawingBoardView extends SurfaceView {

    private Paint erasePaint, rectPaint, circlePaint;
    private Path erasePath, selectPath, triangleTowerPath, trianglePath, equilateralPath, anglePath;
    private List<Path> paintPaths, fillPaths, triangleTowerPaths, trianglePaths, equilateralPaths, anglePaths;
    private List<Paint> paints, fillPaints, rectPaints, circlePaints, ovalPaints, triangleTowerPaints, trianglePaints, equilateralPaints, anglePaints;
    private String pathType = "paintPath";
    private boolean eraseMode = false;
    private List<Rect> rects;
    private List<Circle> circleList;
    private List<RectF> ovals;
    private RectF rectF;
    private float startX, startY, currentX, currentY;
    private boolean isDrawing, drawPath, drawRect, drawCircle, isDrawingCircle, isDrawingOval, drawOval, drawTriangleTower, isDrawingTriangleTower, drawTriangle, isDrawingTriangle, isDrawingEquilateral, drawEquilateral, isDrawingRightAngle, drawRightAngle;
    private Rect rect;
    private Circle circle;
    private int pointX, pointY, radius;
    private float tipX, tipY, leftX, leftY, rightX, rightY, equilateralX;

    public DrawingBoardView(Context context) {
        super(context);
        init();
    }

    public DrawingBoardView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DrawingBoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public DrawingBoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    private void init() {
        erasePaint = new Paint();
        circle = new Circle();
        rect = new Rect();
        triangleTowerPaints = new ArrayList<>();
        triangleTowerPaths = new ArrayList<>();
        ovals = new ArrayList<>();
        trianglePaints = new ArrayList<>();
        trianglePaths = new ArrayList<>();
        rectPaints = new ArrayList<>();
        ovalPaints = new ArrayList<>();
        circlePaints = new ArrayList<>();
        circleList = new ArrayList<>();
        anglePaints = new ArrayList<>();
        anglePath = new Path();
        anglePaths = new ArrayList<>();
        equilateralPaths = new ArrayList<>();
        equilateralPaints = new ArrayList<>();
        circlePaint = new Paint();
        triangleTowerPath = new Path();
        circlePaint.setColor(Color.BLACK);
        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setStrokeWidth(5);
        erasePath = new Path();
        trianglePath = new Path();
        equilateralPath = new Path();
        triangleTowerPath = new Path();
        paints = new ArrayList<>();
        fillPaints = new ArrayList<>();
        fillPaths = new ArrayList<>();
        paintPaths = new ArrayList<>();
        setPaintColor(Color.BLACK);
        rects = new ArrayList<>();
        rectPaint = new Paint();
        rectPaint.setColor(Color.BLACK);
        rectPaint.setStrokeWidth(5);
        rectPaint.setStyle(Paint.Style.STROKE);
        drawPath = true;
        isDrawing = false;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = paints.get(paints.size() - 1);
        if (isDrawing) {
            int left = (int) Math.min(startX, currentX);
            int right = (int) Math.max(startX, currentX);
            int top = (int) Math.min(startY, currentY);
            int bottom = (int) Math.max(startY, currentY);
            rect.set(left, top, right, bottom);
            canvas.drawRect(rect, paint);
            isDrawing = false;
        }
        if (!isDrawing) {
            for (int i = 0; i < rects.size(); i++) {
                canvas.drawRect(rects.get(i), rectPaints.get(i));
            }
        }

        for (int i = 0; i < paintPaths.size(); i++) {
            canvas.drawPath(paintPaths.get(i), paints.get(i));
        }

        for (int i = 0; i < trianglePaths.size(); i++) {
            canvas.drawPath(trianglePaths.get(i), trianglePaints.get(i));
        }
        if (isDrawingCircle) {
            circle.setPointX(pointX);
            circle.setPointY(pointY);
            circle.setRadius(radius);
            canvas.drawCircle(circle.getPointX(), circle.getPointY(), circle.getRadius(), paint);
            isDrawingCircle = false;
        }
        if (!isDrawingCircle) {
            for (int i = 0; i < circleList.size(); i++) {
                canvas.drawCircle(circleList.get(i).getPointX(), circleList.get(i).getPointY(), circleList.get(i).getRadius(), circlePaints.get(i));
            }
        }
        if (isDrawingOval) {
            int left = (int) Math.min(startX, currentX);
            int right = (int) Math.max(startX, currentX);
            int top = (int) Math.min(startY, currentY);
            int bottom = (int) Math.max(startY, currentY);
            rectF.set(left, top, right, bottom);
            canvas.drawOval(rectF, paint);
            isDrawingOval = false;
        }
        if (!isDrawingOval) {
            for (int i = 0; i < ovals.size(); i++) {
                canvas.drawOval(ovals.get(i), ovalPaints.get(i));
            }
        }
        if (isDrawingTriangleTower) {
            float leftX = currentX - (currentX - startX) * 2;
            float leftY = currentY;
            triangleTowerPath.lineTo(leftX, leftY);
            triangleTowerPath.lineTo(currentX, currentY);
            triangleTowerPath.close();
            canvas.drawPath(triangleTowerPath, paint);
            isDrawingTriangleTower = false;
        }

        if (!isDrawingTriangleTower){
            for (int i = 0; i < triangleTowerPaths.size(); i++) {
                canvas.drawPath(triangleTowerPaths.get(i), triangleTowerPaints.get(i));
            }
        }
        if (isDrawingTriangle) {
            trianglePath.reset();
            trianglePath.moveTo(tipX, tipY);
            trianglePath.lineTo(leftX, leftY);
            trianglePath.lineTo(rightX, rightY);
            trianglePath.close();
            canvas.drawPath(trianglePath, paint);
            isDrawingTriangle = false;
        }
        if (isDrawingEquilateral) {
            equilateralPath.reset();
            equilateralPath.moveTo(equilateralX, startY);
            int x = (int) ((currentY - startY) / Math.sqrt(3));
            int rightX = (int) (equilateralX + x);
            int leftX = (int) (equilateralX - x);
            equilateralPath.lineTo(leftX, currentY);
            equilateralPath.lineTo(rightX, currentY);
            equilateralPath.close();
            canvas.drawPath(equilateralPath, paint);
            isDrawingEquilateral = false;
        }
        if (!isDrawingEquilateral) {
            for (int i = 0; i < equilateralPaths.size(); i++) {
                canvas.drawPath(equilateralPaths.get(i), equilateralPaints.get(i));
            }
        }
        if (isDrawingRightAngle) {
            anglePath.reset();
            anglePath.moveTo(startX, startY);
            anglePath.lineTo(startX, currentY);
            anglePath.lineTo(currentX, currentY);
            anglePath.close();
            canvas.drawPath(anglePath, paint);
            isDrawingRightAngle = false;
        }
        if (!isDrawingRightAngle) {
            for (int i = 0; i < anglePaths.size(); i++) {
                canvas.drawPath(anglePaths.get(i), anglePaints.get(i));
            }
        }

        for (int i = 0; i < fillPaths.size(); i++) {
            canvas.drawPath(fillPaths.get(i), fillPaints.get(i));
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        Paint paint = paints.get(paints.size() - 1);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = event.getX();
                startY = event.getY();
                if (drawPath && selectPath != null) {
                    selectPath.moveTo(x, y);
                }
                if (drawRect) {
                    rect = new Rect();
                    rectPaints.add(paint);
                }
                if (drawCircle) {
                    circle = new Circle();
                    circlePaints.add(paint);
                }
                if (drawOval) {
                    rectF = new RectF();
                    ovalPaints.add(paint);
                }
                if (drawTriangleTower) {
                    triangleTowerPaints.add(paint);
                    triangleTowerPath.moveTo(event.getX(), event.getY());
                }
                if (drawTriangle) {
                    trianglePath = new Path();
                    tipY = startY;
                    leftX = startX;
                    trianglePaints.add(paint);
                }
                if (drawEquilateral) {
                    equilateralPath = new Path();
                    equilateralPaints.add(paint);
                }
                if (drawRightAngle) {
                    anglePath = new Path();
                    anglePaints.add(paint);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                currentX = event.getX();
                currentY = event.getY();
                if (drawPath) {
                    selectPath.lineTo(x, y);
                }
                if (drawRect) {
                    isDrawing = true;
                    invalidate();
                }
                if (drawOval) {
                    isDrawingOval = true;
                    invalidate();
                }
                if (drawCircle) {
                    pointX = (int) (startX + (currentX - startX) / 2);
                    pointY = (int) (startY + (currentY - startY) / 2);
                    radius = (int) Math.abs(currentY - startY);
                    isDrawingCircle = true;
                    invalidate();
                }
                if (drawTriangleTower) {
                    isDrawingTriangleTower = true;
                    invalidate();
                }
                if (drawTriangle) {
                    isDrawingTriangle = true;
                    leftY = currentY;
                    tipX = (currentX - leftX) / 2 + leftX;
                    rightX = currentX;
                    rightY = currentY;
                    invalidate();
                }
                if (drawEquilateral) {
                    equilateralX = startX + (currentX - startX) / 2;
                    isDrawingEquilateral = true;
                    invalidate();
                }
                if (drawRightAngle) {
                    isDrawingRightAngle = true;
                    invalidate();
                }

                break;
            case MotionEvent.ACTION_UP:
                if (drawRect) {
                    rects.add(rect);
                    isDrawing = false;
                }
                if (drawCircle) {
                    circleList.add(circle);
                    isDrawingCircle = false;
                }
                if (drawOval) {
                    ovals.add(rectF);
                    isDrawingOval = false;
                }
                if (drawTriangleTower) {
                    triangleTowerPaths.add(triangleTowerPath);
                    isDrawingTriangleTower = false;
                }
                if (drawTriangle) {
                    trianglePaths.add(trianglePath);
                    isDrawingTriangle = false;
                }
                if (drawEquilateral) {
                    equilateralPaths.add(equilateralPath);
                    isDrawingEquilateral = false;
                }
                if (drawRightAngle) {
                    anglePaths.add(anglePath);
                    isDrawingRightAngle = false;
                }
                break;
        }
        invalidate();
        return true;
    }

    public void clearBoard() {
        for (int i = 0; i < paintPaths.size(); i++) {
            paintPaths.get(i).reset();
        }
        for (int i = 0; i < fillPaths.size(); i++) {
            fillPaths.get(i).reset();
        }
        for (int i = 0; i < triangleTowerPaths.size(); i++) {
            triangleTowerPaths.get(i).reset();
        }
        for (int i = 0; i < trianglePaths.size(); i++) {
            trianglePaths.get(i).reset();
        }
        for (int i = 0; i < equilateralPaths.size(); i++) {
            equilateralPaths.get(i).reset();
        }
        for (Path path : anglePaths) {
            path.reset();
        }
        rects.clear();
        ovals.clear();
        circleList.clear();
        erasePath.reset();
        eraseMode = false;
        invalidate();
    }

    public void setPaint(String type) {
        switch (type) {
            case "paint":
                selectPath = paintPaths.get(paintPaths.size() - 1);
                this.pathType = "paintPath";
                drawPath = true;
                drawRect = false;
                drawCircle = false;
                drawOval = false;
                drawTriangle = false;
                drawTriangleTower = false;
                drawEquilateral = false;
                drawRightAngle = false;
                break;
            case "fillPaint":
                selectPath = fillPaths.get(fillPaths.size() - 1);
                this.pathType = "fillPath";
                drawPath = true;
                drawRect = false;
                drawCircle = false;
                drawOval = false;
                drawTriangle = false;
                drawTriangleTower = false;
                drawEquilateral = false;
                drawRightAngle = false;
                break;
            case "rect":
                drawPath = false;
                drawRect = true;
                drawCircle = false;
                drawOval = false;
                drawTriangle = false;
                drawTriangleTower = false;
                drawRightAngle = false;
                drawEquilateral = false;
                break;
            case "drawCircle":
                drawRect = false;
                drawPath = false;
                drawOval = false;
                drawCircle = true;
                drawTriangle = false;
                drawTriangleTower = false;
                drawEquilateral = false;
                drawRightAngle = false;
                break;
            case "drawOval":
                drawPath = false;
                drawRect = false;
                drawCircle = false;
                drawOval = true;
                drawTriangle = false;
                drawTriangleTower = false;
                drawEquilateral = false;
                drawRightAngle = false;
                break;
            case "drawTriangleTower":
                drawPath = false;
                drawRect = false;
                drawCircle = false;
                drawOval = false;
                drawTriangle = false;
                drawTriangleTower = true;
                drawEquilateral = false;
                drawRightAngle = false;
                break;
            case "drawTriangle":
                drawPath = false;
                drawRect = false;
                drawCircle = false;
                drawOval = false;
                drawTriangleTower = false;
                drawTriangle = true;
                drawRightAngle = false;
                drawEquilateral = false;
                break;
            case "drawEquilateral":
                drawPath = false;
                drawRect = false;
                drawCircle = false;
                drawOval = false;
                drawTriangleTower = false;
                drawTriangle = false;
                drawRightAngle = false;
                drawEquilateral = true;
                break;
            case "drawRightAngle":
                drawPath = false;
                drawRect = false;
                drawCircle = false;
                drawOval = false;
                drawTriangleTower = false;
                drawTriangle = false;
                drawEquilateral = false;
                drawRightAngle = true;
                break;
        }
    }

    public void setPaintColor(int color) {
        Paint paint = new Paint();
        paint.setColor(color);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeWidth(3);
        paints.add(paint);
        Paint fillPaint = new Paint();
        fillPaint.setColor(color);
        fillPaint.setStyle(Paint.Style.STROKE);
        fillPaint.setStrokeWidth(20);
        fillPaint.setAntiAlias(true);
        fillPaint.setDither(true);
        fillPaint.setAlpha(250);
        fillPaint.setStrokeJoin(Paint.Join.ROUND);
        fillPaint.setStrokeCap(Paint.Cap.ROUND);
        fillPaints.add(fillPaint);
        Path path = new Path();
        Path fillPath = new Path();
        Path triangleTowerPath = new Path();
        this.triangleTowerPath = triangleTowerPath;
        this.triangleTowerPaints.add(paint);
        triangleTowerPaths.add(triangleTowerPath);
        Path trianglePath = new Path();
        trianglePaths.add(trianglePath);
        trianglePaints.add(paint);
        fillPaths.add(fillPath);
        paintPaths.add(path);
        Path anglePath = new Path();
        anglePaths.add(anglePath);
        this.anglePath = anglePath;
        this.anglePaints.add(paint);
        Path equilateralPath = new Path();
        this.equilateralPath = equilateralPath;
        equilateralPaths.add(equilateralPath);
        equilateralPaints.add(paint);
        if (pathType.equals("paintPath")) {
            selectPath = path;
        } else {
            selectPath = fillPath;
        }
    }

    public void setEraseMode() {
        eraseMode = true;
        drawPath = true;
        drawRect = false;
        drawTriangleTower = false;
        drawTriangle = false;
        drawCircle = false;
        drawEquilateral = false;
        drawRightAngle = false;
        erasePath = new Path();
        erasePaint.setAntiAlias(true);
        erasePaint.setDither(true);
        erasePaint.setStrokeWidth(30);
        erasePaint.setStyle(Paint.Style.STROKE);
        erasePaint.setStrokeJoin(Paint.Join.ROUND);
        erasePaint.setStrokeCap(Paint.Cap.SQUARE);
        erasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        selectPath = erasePath;
    }

    private class Circle {
        int pointX;
        int pointY;
        int radius;

        public int getPointX() {
            return pointX;
        }

        public void setPointX(int pointX) {
            this.pointX = pointX;
        }

        public int getPointY() {
            return pointY;
        }

        public void setPointY(int pointY) {
            this.pointY = pointY;
        }

        public int getRadius() {
            return radius;
        }

        public void setRadius(int radius) {
            this.radius = radius;
        }
    }
}

三、总结

绘制主要用到Paint和Path,大体思路都是监听OnTouchEvent事件,绘制路径或者其他图案,开发这个项目用时一周。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/90982.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

4.17 如何基于 UDP 协议实现可靠传输?

目录 QUIC 是如何实现可靠传输的&#xff1f; Packet Header QUIC Frame Header QUIC 是如何解决 TCP 队头阻塞问题的&#xff1f; 什么是TCP对头阻塞问题&#xff1a; HTTP/2 的队头阻塞: 没有队头阻塞的 QUIC QUIC 是如何做流量控制的&#xff1f; QUIC 实现流量控制…

探索未来世界,解密区块链奥秘!

你是否曾好奇&#xff0c;区块链是如何影响着我们的生活与未来&#xff1f;想要轻松了解这个引领着技术革命的概念吗&#xff1f;那么这本令人着迷的新书《区块链导论》绝对值得你拥有&#xff01; 内容丰富多彩&#xff0c;让你轻松掌握&#xff1a; **1章&#xff1a;区块链…

MyBatis与Spring整合以及AOP和PageHelper分页插件整合

目录 前言 一、MyBatis与Spring整合的好处以及两者之间的关系 1.好处 2.关系 二、MyBatis和Spring集成 1.导入pom.xml 2.编写配置文件 3.利用mybatis逆向工程生成模型层代码 三、常用注解 四、AOP整合pageHelper分页插件 创建一个切面 测试 前言 MyBatis是一个开源的…

Unity 图片资源的适配

前言 最近小编做Unity项目时&#xff0c;发现在资源处理这方面和Android有所不同&#xff1b;例如&#xff1a;Android的资源文件夹res下会有着mipmap-mdpi&#xff0c;mipmap-hdpi&#xff0c;mipmap-xhdpi&#xff0c;mipmap-xxhdpi&#xff0c;mipmap-xxxhdpi这五个文件夹&a…

数据通信——TCP(三次握手及基础特性)

引言 TCP&#xff08;传输控制协议&#xff09;&#xff0c;不像之前的UDP那样&#xff0c;因为这个协议要将很多复杂的东西&#xff0c;所以这次的特性是简单的特性&#xff0c;后续会讲一些复杂难懂的知识&#xff0c;这次先说一些TCP明显的特性 面向连接 TCP提供了对连接的管…

CSS笔记

介绍 CSS导入方式 三种方法都将文字设置成了红色 CSS选择器 元素选择器 id选择器 图中div将颜色控制为红色&#xff0c;#name将颜色控制为蓝色&#xff0c;谁控制的范围最小&#xff0c;谁就生效&#xff0c;所以第二个div是蓝色的。id属性值要唯一&#xff0c;否则报错。 clas…

Dockerfile搭建LNMP运行Wordpress平台

Dockerfile搭建LNMP运行Wordpress平台 一、项目1.1 项目环境1.2 服务器环境1.3 任务需求 二、Linux 系统基础镜像三、Nginx1、建立工作目录2、编写 Dockerfile 脚本3、准备 nginx.conf 配置文件4、生成镜像5、创建自定义网络6、启动镜像容器7、验证 nginx 四、Mysql1、建立工作…

KVM创建虚拟机可访问外网+可使用Xshell等工具连接

创建虚拟机时使用桥接网络模块即可&#xff0c;如下&#xff1a; 1、创建一个存储卷(虚拟机的磁盘) 2、创建虚拟机时选择网络 3、系统安装完成后配置固定IP地址 vi /etc/sysconfig/network-scripts/ifcfg-eth0ONBOOTyes BOOTPROTOstatic IPADDR16.32.15.60 GATEWAY16.32.15.2…

DevOps团队如何提高Kubernetes性能

今天&#xff0c;Kubernetes仍然是开发人员最需要的容器。Kubernets最初由 Google 工程师开发&#xff0c;作为跨本地、公共云、私有云或混合云托管的首选解决方案享誉全球。 来自Statista的报告显示&#xff0c;公共云中的Kubernetes市场份额在过去一年中上升了近30%。并且在…

Stable Diffusion 系列教程 | 打破模型壁垒

目录 1.模型基本分类 1.1 CheckPoint 大模型/底模型/主模型 1.2 VAE美化模型/变分自编码器 1.3 HyperNetwork 超网络 1.4 embeddings&#xff08;/Textual Inversion&#xff09; 嵌入式向量 1.5 loRa 低秩适应模型 2. 下载途径和渠道 2.1 C站 2.1.1 如何筛选到自己需…

【docker】运行registry

registry简介 Docker registry是docker镜像仓库的服务,用于存储和分发docker镜像。 Docker registry主要特点和功能: 存储docker镜像:提供持久化存储docker镜像的功能,存储镜像的各个layer。 分发镜像:拉取和推送镜像的去中心化存储和分发服务。 支持版本管理:给镜像打标签…

离谱事件解决方法2 无法定位程序输入点XXX于动态链接库XXX.dll

事情经过&#xff1a; 本人一只acmer&#xff0c;使用sublime编写代码&#xff0c;但是前两天在打开cpp类型的文件的时候显示报错如下&#xff1a; 这里的dll文件就是动态链接库&#xff0c;它并不是一个可执行文件&#xff0c;里面存放的是程序的函数实现过程&#xff08;公用…

【面试题】MVC、MVP与MVVM模式是什么?

MVC模式 MVC是应用最广泛的软件架构之一&#xff0c;一般MVC分为&#xff1a; Model&#xff08; 模型 &#xff09;、Controller&#xff08; 控制器 &#xff09;、View&#xff08; 视图 &#xff09;。 这主要是基于分层的目的&#xff0c;让彼此的职责分开。View 一般…

EWM是什么

EWM是SAP的一个模块&#xff0c;代表扩展仓库管理&#xff08;Extended Warehouse Management&#xff09;&#xff0c;是SAP企业资源计划&#xff08;ERP&#xff09;的一部分。它提供了一个完整的、高级的仓库管理解决方案&#xff0c;支持企业在全球范围内的仓库管理、订单管…

帮助中心应该用什么工具做?

在线帮助中心是指一个位于互联网上的资源平台&#xff0c;提供给用户获取产品或服务相关信息、解决问题以及获取技术支持的渠道。它通常包含了组织化的知识库、常见问题解答&#xff08;FAQ&#xff09;、操作指南、教程视频、用户手册等内容。在线帮助中心的主要目标是为用户提…

SQL Server、MySQL和Oracle数据库分页查询的区别与联系

摘要&#xff1a;本文将通过一个现实例子&#xff0c;详细解释SQL Server、MySQL和Oracle这三种常见关系型数据库在分页查询方面的区别与联系。我们将提供具体场景下的SQL语句示例&#xff0c;并解释每个数据库的分页查询用法以及优化方法&#xff0c;帮助读者更好地选择适合自…

LeetCode-227-基本计算器Ⅱ

题目描述&#xff1a; 给你一个字符串表达式 s &#xff0c;请你实现一个基本计算器来计算并返回它的值。 整数除法仅保留整数部分。 你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。 注意&#xff1a;不允许使用任何将字符串作为数学表达式计…

DevOps中的持续测试优势和工具

持续测试 DevOps中的持续测试是一种软件测试类型&#xff0c;它涉及在软件开发生命周期的每个阶段测试软件。持续测试的目标是通过早期测试和经常测试来评估持续交付过程的每一步的软件质量。 DevOps中的持续测试流程涉及开发人员、DevOps、QA和操作系统等利益相关者。 持续…

JVM及垃圾回收机制

文章目录 1、JVM组成&#xff1f;各部分作用&#xff1f;1.1 类加载器&#xff08;Class Loaders&#xff09;1.2 运行时数据区&#xff08;Runtime Data Area&#xff09;1.3 执行引擎&#xff08;Execution Engine&#xff09;1.4 本地方法接口&#xff08;Native Interface&…

【PHP】数据类型运算符位运算

文章目录 数据类型简单&#xff08;基本&#xff09;数据类型&#xff1a;4个小类复合数据类型&#xff1a;2个小类特殊数据类型&#xff1a;2个小类类型转换类型判断整数类型浮点类型布尔类型 运算符赋值运算符算术运算符比较运算符逻辑运算符连接运算符错误抑制符三目运算符自…