Android画板
LinePoint类定义
package com.example.myapplication;
public class LinePoint {
float lineStartX;
float lineStartY;
float lineStopX;
float lineStopY;
public LinePoint(float lineStartX, float lineStartY, float lineStopX, float lineStopY) {
this.lineStartX = lineStartX;
this.lineStartY = lineStartY;
this.lineStopX = lineStopX;
this.lineStopY = lineStopY;
}
}
MyView.java
package com.example.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class MyView extends View {
// 定义了几种绘制模式
public static final int MODE_LINE = 1;
public static final int MODE_CIRCLE = 2;
public static final int MODE_RECT = 3;
int mode = MODE_LINE;
Paint paint = new Paint();
List<LinePoint> linePointList = new ArrayList<>();
float lineStartX;
float lineStartY;
float lineStopX;
float lineStopY;
// 圆心和半径
float circleX;
float circleY;
float circleRadius;
// 矩形
float rectStartX;
float rectStartY;
float rectStopX;
float rectStopY;
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paint.setStrokeWidth(4);
paint.setDither(true);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
Log.e("MyView onTouchEvent", "x = " + x + " y = " + y);
// 如果是划线模式
if (mode == MODE_LINE) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lineStartX = x;
lineStartY = y;
break;
case MotionEvent.ACTION_MOVE:
lineStopX = x;
lineStopY = y;
invalidate();
break;
case MotionEvent.ACTION_UP:
LinePoint linePoint = new LinePoint(lineStartX, lineStartY, lineStopX, lineStopY);
linePointList.add(linePoint);
lineStartX=0;
lineStartY=0;
lineStopX=0;
lineStopY=0;
invalidate();
break;
}
}
// 如果是画圆模式
else if(mode == MyView.MODE_CIRCLE){
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
circleX = x;
circleY = y;
break;
case MotionEvent.ACTION_MOVE:
// 计算半径
circleRadius = (float) Math.sqrt((x-circleX)*(x-circleX) + (y-circleY)*(y-circleY));
invalidate();
break;
case MotionEvent.ACTION_UP:
break;
}
}
// 如果是矩形模式
else if(mode == MyView.MODE_RECT){
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
rectStartX = x;
rectStartY = y;
break;
case MotionEvent.ACTION_MOVE:
rectStopX = x;
rectStopY = y;
invalidate();
break;
case MotionEvent.ACTION_UP:
break;
}
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
for (LinePoint linePoint : linePointList) {
canvas.drawLine(linePoint.lineStartX, linePoint.lineStartY, linePoint.lineStopX,
linePoint.lineStopY, paint);
}
canvas.drawLine(lineStartX, lineStartY, lineStopX, lineStopY, paint);
canvas.drawCircle(circleX, circleY, circleRadius, paint);
canvas.drawRect(rectStartX, rectStartY, rectStopX, rectStopY, paint);
}
public void addPaintWidth() {
float strokeWidth = paint.getStrokeWidth();
paint.setStrokeWidth(strokeWidth + 1);
}
public void subPaintWidth() {
float strokeWidth = paint.getStrokeWidth();
paint.setStrokeWidth(strokeWidth - 1);
}
public void setPaintColor(int color) {
paint.setColor(color);
}
public void setDrawMode(int mode) {
this.mode = mode;
}
public void updoDraw() {
linePointList.remove(linePointList.size()-1);
invalidate();
}
}
MainActivity.java
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button btn1;
private Button btn2;
private Button btn3;
private Button btn4;
private Button btn5;
private Button btn6;
private Button btn7;
private Button btn8;
private MyView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = findViewById(R.id.btn1);
btn2 = findViewById(R.id.btn2);
btn3 = findViewById(R.id.btn3);
btn4= findViewById(R.id.btn4);
btn5= findViewById(R.id.btn5);
btn6= findViewById(R.id.btn6);
btn7= findViewById(R.id.btn7);
btn8 = findViewById(R.id.btn8);
myView = findViewById(R.id.myView);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.addPaintWidth();
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.subPaintWidth();
}
});
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setPaintColor(Color.RED);
}
});
btn4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setPaintColor(Color.BLACK);
}
});
btn5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setDrawMode(MyView.MODE_LINE);
}
});
btn6.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setDrawMode(MyView.MODE_CIRCLE);
}
});
btn7.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setDrawMode(MyView.MODE_RECT);
}
});
btn8.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.updoDraw();
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
Log.e("MainActivity", "x = " + x + " y = " + y);
return super.onTouchEvent(event);
}
}
activity_mail.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<com.example.myapplication.MyView
android:id="@+id/myView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="50dp"
app:layout_constraintBottom_toBottomOf="parent">
<LinearLayout
android:layout_width="1000dp"
android:layout_height="50dp"
android:background="@color/teal_200">
<Button
android:id="@+id/btn8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="撤销" />
<Button
android:id="@+id/btn5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="划线" />
<Button
android:id="@+id/btn6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="圆形" />
<Button
android:id="@+id/btn7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="矩形" />
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加粗" />
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="变细" />
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="红色" />
<Button
android:id="@+id/btn4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="黑色" />
</LinearLayout>
</HorizontalScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
绘制路径Path
新建一个PathPaint类型 保存每一笔的路径和笔的状态
package com.example.demo;
import android.graphics.Paint;
import android.graphics.Path;
public class PathPaint {
Path path;
Paint paint;
public PathPaint(Path path, Paint paint) {
this.path = path;
this.paint = paint;
}
}
在主界面中增加两个菜单 红色 和 蓝色 点击后设置Myview中Paint的颜色
代码如下
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setPaintColor(Color.RED);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setPaintColor(Color.BLUE);
}
});
Myview代码如下:
package com.example.demo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class MyView extends View {
List<PathPaint> pathPaintList = new ArrayList<>();
Path path = new Path();
Paint paint = new Paint();
private int color;
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onDraw(Canvas canvas) {
for(PathPaint pathPaint : pathPaintList){
canvas.drawPath(pathPaint.path, pathPaint.paint);
}
canvas.drawPath(path, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
path.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
PathPaint pathPaint = new PathPaint(path, paint);
pathPaintList.add(pathPaint);
path = new Path();
paint = new Paint();
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(color);
invalidate();
break;
}
return true;
}
public void setPaintColor(int color) {
this.color = color;
paint.setColor(color);
}
}
绘制图片
1.定义ImgParam类 保存图片位置和资源ID
package com.example.myapplication;
public class ImgParam {
float imgX;
float imgY;
int imgId;
public ImgParam(float imgX, float imgY, int imgId) {
this.imgX = imgX;
this.imgY = imgY;
this.imgId = imgId;
}
}
2.MyView中增加绘制图片的模式
package com.example.myapplication;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class MyView extends View {
public static final int DRAW_PATH = 1;
public static final int DRAW_IMG = 2;
Path path = new Path();
Paint paint = new Paint();
int mode = DRAW_PATH;
List<ImgParam> imgParamList =new ArrayList<>();
// 绘图的位置
float imgX;
float imgY;
int imgId;
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
if(imgId != 0) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgId);
canvas.drawBitmap(bitmap, imgX, imgY, paint);
}
for (ImgParam imgParam : imgParamList){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgParam.imgId);
canvas.drawBitmap(bitmap, imgParam.imgX, imgParam.imgY, paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (mode == DRAW_PATH) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
break;
}
} else if (mode == DRAW_IMG) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
imgX = x;
imgY = y;
invalidate();
break;
case MotionEvent.ACTION_UP:
ImgParam imgParam = new ImgParam(x, y, imgId);
imgParamList.add(imgParam);
this.imgId = 0;
break;
}
}
return true;
}
public void setDrawMode(int mode) {
this.mode = mode;
}
public void setDrawImgId(int imgId) {
this.imgId = imgId;
}
}
3.布局文件中增加菜单
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<com.example.myapplication.MyView
android:id="@+id/myView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
app:layout_constraintBottom_toBottomOf="parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Path"
android:id="@+id/btn1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="贴图1"
android:id="@+id/btn2"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="贴图2"
android:id="@+id/btn3"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
4.在MainActivity中处理菜单事件
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button btn1;
private Button btn2;
private Button btn3;
private MyView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = findViewById(R.id.btn1);
btn2 = findViewById(R.id.btn2);
btn3 = findViewById(R.id.btn3);
myView = findViewById(R.id.myView);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setDrawMode(MyView.DRAW_PATH);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setDrawMode(MyView.DRAW_IMG);
myView.setDrawImgId(R.drawable.smile);
}
});
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myView.setDrawMode(MyView.DRAW_IMG);
myView.setDrawImgId(R.drawable.ren);
}
});
}
}