当前位置: 首页 > 工具软件 > DrawView > 使用案例 >

自定义画图的控件DrawView,可做草稿页面

金何平
2023-12-01

Android开发中,有时需要一个半透明的草稿界面,上面可当草稿纸一样画图,还可以撤销、恢复和清除。

为此做了个简单的DrawView控件,包含了以上的功能,代码如下DrawView.java:

package com.ldw.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.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

/**
 * 说明:自定义画图控件,继承View
 * @author ldw
 * 日期:2017.12.13
 */
public class DrawView extends View {

    //画笔
	private Paint mPaint = null;
    //绘制的记录
    private List<Path> mPathList = new ArrayList<>();
    //丢弃的记录,redo用
    private List<Path> mRecycleList = new ArrayList<>();

    //临时变量
    private float preX;
    private float preY;
    private Path path;

	public DrawView(Context context, AttributeSet attrs) {
		super(context, attrs);
        //设置抖动处理
		mPaint = new Paint(Paint.DITHER_FLAG);
        //设置画笔颜色
		mPaint.setColor(Color.BLACK);
		//设置画笔风格
		mPaint.setStyle(Style.STROKE);
		mPaint.setStrokeWidth(3);
		//反锯齿
		mPaint.setAntiAlias(true);
		mPaint.setDither(true);
		// 设置外边缘
		mPaint.setStrokeJoin(Paint.Join.ROUND);
		// 圆形样式
		mPaint.setStrokeCap(Paint.Cap.ROUND);
    }

	@Override
	public boolean onTouchEvent(MotionEvent event){
		float x = event.getX();
		float y = event.getY();
		switch(event.getAction()){
			case MotionEvent.ACTION_DOWN:
			    path = new Path();
                mPathList.add(path);
                mRecycleList.clear();
                preX = x;
                preY = y;
				path.moveTo(x, y);
				break;
			case MotionEvent.ACTION_MOVE:
				float dx = Math.abs(x - preX);
				float dy = Math.abs(y - preY);
				if(dx >= 2.0 || dy >= 2.0){
					/*
					 * 二次贝塞尔曲线参数说明:
					 * 控制点:为每次event获得的点(x, y)
					 * 起点和终点:为获得的点(x, y)的一系列中间点。
					 * 说明:这样贝塞尔曲线一般是不会经过(x, y)(除非是直线的时候),而是经过所有中间点。
					 * 		 但却能保证曲线向(x, y)的方向弯曲。
					 * 		 如果终点设置为(x, y),控制点很难去计算。
					 * 缺点:根据贝塞尔曲线公式可以知道:控制点和启动终点共线的话,曲线段变成直线。
					 * 		 刚开始绘线的一小段会变成直线,因为起点和控制点重叠,不过效果很不明显。
					 * 		 如果是path.quadTo(preX, preY, x, y);也变成画直线,跟path.lineTo(x,y);一样效果
					 */
					//二次贝塞尔曲线:控制点设置为起点,终点设置为中间点
					path.quadTo(preX, preY, (preX + x)/2, (preY + y)/2);
					preX = x;
					preY = y;
				}
				break;
			case MotionEvent.ACTION_UP:
				path.lineTo(x, y);
				break;
		}
		invalidate();
		return true;
	}

	@Override
	public void onDraw(Canvas canvas){
		for(Path path : mPathList){
            canvas.drawPath(path, mPaint);
        }
	}

    /**
     * 能否撤销
     */
	public boolean canUndo(){
        return mPathList.size() > 0;
    }

    /**
     * 能否恢复
     */
    public boolean canRedo(){
        return mRecycleList.size() > 0;
    }

    /**
     * 撤销
     */
	public void undo() {
        if(canUndo()){
            mRecycleList.add(mPathList.remove(mPathList.size() - 1));
            invalidate();
        }
	}

    /**
     * 恢复
     */
	public void redo(){
        if(canRedo()){
            mPathList.add(mRecycleList.remove(mRecycleList.size() - 1));
            invalidate();
        }
    }

    /**
     * 清除全部
     */
	public void clear() {
        mRecycleList.clear();
		if(canUndo()) {
            mPathList.clear();
            invalidate();
        }
	}

	/**
	 * 设置画笔大小
	 */
	public void setPaintWidth(int width) {
		mPaint.setStrokeWidth(width);
	}



}
Activity中使用如下:

1、activity要设置半透明的背景,主题要加上:

<item name="android:windowBackground">@color/translucentWindow</item>//半透明值为#7fffffff
        <item name="android:windowIsTranslucent">true</item>
2、把控件放进布局,使用提供的几个接口,很简单,不详细说了。



 类似资料: