【安卓】自定义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事件,绘制路径或者其他图案,开发这个项目用时一周。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
实现 Android 自定义对号,可以使用自定义 View 实现打钩动画功能。以下是实现方法: 首先,创建一个类来实现自定义 View,这个类需要继承自 View,然后重写 onDraw 方法。在 onDraw 方法中,使用 Canvas 和 Path 对象来绘制对号的形状。 在绘制对号之前,需要先设置对号的起点和终点坐标,可以通过计算 View 的宽度和高度来确定这些坐标。然后,使用 Path 对象来创建对号的形状,具体方法如下: 1. 创建一个 Path 对象。 2. 使用 moveTo 方法将画笔移动到对号的起点。 3. 使用 lineTo 方法将画笔画出对号的一条线段。 4. 使用 moveTo 方法将画笔移动到对号的另一个起点。 5. 使用 lineTo 方法将画笔画出对号的另一条线段。 在绘制 Path 对象之后,可以使用 Paint 对象来设置对号的样式,例如颜色和宽度等。最后,在 onDraw 方法中调用 Canvas 的 drawPath 方法来将对号绘制出来。 另外,为了实现打钩动画,还需要使用 ValueAnimator 对象来控制 Path 的绘制过程。具体方法如下: 1. 创建一个 ValueAnimator 对象,并设置动画的起始值和结束值。 2. 在动画的监听器中,使用 ValueAnimator 的 getAnimatedValue 方法来获取当前动画的进度。 3. 根据当前进度,计算出对号的绘制进度,并使用 PathMeasure 对象来获取对应位置的 Path。 4. 在 onDraw 方法中,使用 Canvas 的 drawPath 方法来绘制当前的 Path。 最后,将自定义 View 添加到布局中即可实现自定义对号的功能
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值