版权声明:本文为Zhang Phil原创文章,请不要转载! https://blog.csdn.net/zhangphil/article/details/87810653
先看运行效果:
关键的PaintView:
package com.zhangphil;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
public class PaintView extends View {
public class DrawPath {
Path path;
Paint paint;
}
private Paint paint;
private Path path;
private float downX, downY;
private float tempX, tempY;
private int paintWidth = 10;
private List<DrawPath> drawPathList;
private List<DrawPath> savePathList;
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PaintView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
drawPathList = new ArrayList<>();
savePathList = new ArrayList<>();
initPaint();
}
private void initPaint() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(paintWidth);
paint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (drawPathList != null && !drawPathList.isEmpty()) {
for (DrawPath drawPath : drawPathList) {
if (drawPath.path != null) {
canvas.drawPath(drawPath.path, drawPath.paint);
}
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
path = new Path();//每次手指下去都是一条新的路径
path.moveTo(downX, downY);
DrawPath drawPath = new DrawPath();
drawPath.paint = paint;
drawPath.path = path;
drawPathList.add(drawPath);
invalidate();
tempX = downX;
tempY = downY;
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
float moveY = event.getY();
path.quadTo(tempX, tempY, moveX, moveY);
invalidate();
tempX = moveX;
tempY = moveY;
break;
case MotionEvent.ACTION_UP:
initPaint();//每次手指抬起都要重置下画笔,不然画笔会保存了之前的设置什么画笔的属性会引起bug
break;
}
return true;
}
/**
* 撤销功能。
*/
public void undo() {
if (drawPathList != null && drawPathList.size() >= 1) {
savePathList.add(drawPathList.get(drawPathList.size() - 1));
drawPathList.remove(drawPathList.size() - 1);
invalidate();
}
}
/**
* 反撤销功能。重新生效。
*/
public void reundo() {
if (savePathList != null && !savePathList.isEmpty()) {
drawPathList.add(savePathList.get(savePathList.size() - 1));
savePathList.remove(savePathList.size() - 1);
invalidate();
}
}
/**
* 改变画笔颜色。
*
* @param color
*/
public void resetPaintColor(int color) {
paint.setColor(color);
}
/**
* 放大就是改变画笔的宽度。线条变粗。
*/
public void resetPaintWidth() {
paintWidth += 2;
paint.setStrokeWidth(paintWidth);
}
/**
* 橡皮擦功能。
* 原理是把画笔的颜色和view的背景颜色一样就,然后把画笔的宽度变大了,擦除的时候显得擦除范围大点。
*/
public void eraser() {
paint.setColor(Color.WHITE);//这是view背景的颜色
paint.setStrokeWidth(paintWidth + 6);
}
}
剩下的就是使用。写一个xml布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff">
<RelativeLayout
android:id="@+id/rl_left"
android:layout_width="100dp"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_undo"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="撤销" />
<Button
android:id="@+id/btn_do"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_below="@id/btn_undo"
android:text="反撤销" />
<Button
android:id="@+id/btn_red"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_below="@id/btn_do"
android:text="红色" />
<Button
android:id="@+id/btn_blue"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_below="@id/btn_red"
android:text="蓝色" />
<Button
android:id="@+id/btn_green"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_below="@id/btn_blue"
android:text="绿色" />
<Button
android:id="@+id/btn_scral"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_below="@id/btn_green"
android:text="放大" />
<Button
android:id="@+id/btn_eraser"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_below="@id/btn_scral"
android:text="橡皮擦" />
</RelativeLayout>
<com.zhangphil.PaintView
android:id="@+id/paint_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="@id/rl_left" />
</RelativeLayout>
测试的Activity:
package zhangphil.test;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.zhangphil.PaintView;
public class DrawActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnUndo;
private Button btnDo;
private Button btnRed;
private Button btnBlue;
private Button btnGreen;
private Button btnScral; //放大。
private Button btnEraser; //橡皮擦。
private PaintView paintView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
}
private void initListener() {
btnUndo.setOnClickListener(this);
btnDo.setOnClickListener(this);
btnRed.setOnClickListener(this);
btnBlue.setOnClickListener(this);
btnGreen.setOnClickListener(this);
btnScral.setOnClickListener(this);
btnEraser.setOnClickListener(this);
}
private void initView() {
paintView = (findViewById(R.id.paint_view));
btnUndo = findViewById(R.id.btn_undo);
btnDo = findViewById(R.id.btn_do);
btnRed = findViewById(R.id.btn_red);
btnBlue = findViewById(R.id.btn_blue);
btnGreen = findViewById(R.id.btn_green);
btnScral = findViewById(R.id.btn_scral);
btnEraser = findViewById(R.id.btn_eraser);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_undo:
paintView.undo();
return;
case R.id.btn_do:
paintView.reundo();
return;
case R.id.btn_red:
paintView.resetPaintColor(Color.RED);
return;
case R.id.btn_green:
paintView.resetPaintColor(Color.GREEN);
return;
case R.id.btn_blue:
paintView.resetPaintColor(Color.BLUE);
return;
case R.id.btn_scral:
paintView.resetPaintWidth();
break;
case R.id.btn_eraser:
paintView.eraser();
break;
}
}
}