Java Android:如何移动我的画布可绘制形状 我正在尝试在Android中实现一个绘图应用程序,用户应该能够选择和移动绘制的形状。 目前,我已经在绘图画布上静态绘制了一些矩形和文本 我想选择(在所选形状上绘制边框)并在绘图画布的onTouch事件中移动绘制的
Android:如何移动我的画布可绘制形状Java Android:如何移动我的画布可绘制形状 我正在尝试在Android中实现一个绘图应用程序,用户应该能够选择和移动绘制的形状。 目前,我已经在绘图画布上静态绘制了一些矩形和文本 我想选择(在所选形状上绘制边框)并在绘图画布的onTouch事件中移动绘制的,java,android,Java,Android,Android:如何移动我的画布可绘制形状 我正在尝试在Android中实现一个绘图应用程序,用户应该能够选择和移动绘制的形状。 目前,我已经在绘图画布上静态绘制了一些矩形和文本 我想选择(在所选形状上绘制边框)并在绘图画布的onTouch事件中移动绘制的形状 package com.android.graphics; 导入android.content.Context; 导入android.graphics.Bitmap; 导入android.graphics.Bitmap.CompressF
onTouch
事件中移动绘制的形状package com.android.graphics;
导入android.content.Context;
导入android.graphics.Bitmap;
导入android.graphics.Bitmap.CompressFormat;
导入android.graphics.BitmapFactory;
导入android.graphics.Canvas;
导入android.graphics.Color;
导入android.graphics.Paint;
导入android.graphics.Path;
导入android.graphics.PathEffect;
导入android.graphics.PorterDuff;
导入android.graphics.PorterDuffXfermode;
导入android.graphics.RectF;
导入android.graphics.Typeface;
导入android.util.AttributeSet;
导入android.view.MotionEvent;
导入android.view.view;
导入java.io.ByteArrayOutputStream;
导入java.util.ArrayList;
导入java.util.List;
公共类画布视图扩展视图{
公共枚举模式{
画
文本,
橡皮擦;
}
公共枚举抽屉{
笔,
行,,
矩形,
圆圈
椭圆,
二次贝塞尔,
库比克·贝塞尔;
}
私有画布=null;
私有位图=空;
私有列表路径列表=新的ArrayList();
私有列表paintlist=new ArrayList();
私有最终油漆清空油漆=新油漆();
private int baseColor=Color.WHITE;
//要撤消,请重做
私有int历史指针=0;
//旗帜
私有模式=模式.DRAW;
私人抽屉=Drawer.PEN;
私有布尔值isDown=false;
//油漆
private Paint.Style paintStyle=Paint.Style.STROKE;
private int paintStrokeColor=Color.BLACK;
私有int paintFillColor=Color.BLACK;
专用浮子油漆冲程宽度=3F;
私有整数不透明度=255;
私有浮动模糊=0F;
private Paint.Cap lineCap=Paint.Cap.ROUND;
private PathEffect drawPathEffect=null;
//用于文本
私有字符串text=“”;
private Typeface fontFamily=Typeface.DEFAULT;
私有浮动字体大小=32F;
private Paint.Align text Align=Paint.Align.RIGHT;//已修复
私有绘画文本绘画=新绘画();
私有浮动文本x=0F;
私有浮动文本y=0F;
//抽屉
专用浮点数startX=0F;
私人浮动起点=0F;
专用浮点控制x=0F;
私有浮动控制y=0F;
公共画布视图(上下文、属性集属性、int-defStyle){
超级(上下文、属性、定义样式);
这个.setup();
}
公共画布视图(上下文、属性集属性){
超级(上下文,attrs);
这个.setup();
}
公共画布视图(上下文){
超级(上下文);
这个.setup();
}
私有无效设置(){
this.pathLists.add(新路径());
this.paintlist.add(this.createPaint());
这个.historyPointer++;
this.textPaint.setARGB(0,255,255,255);
}
私有绘制createPaint(){
油漆=新油漆();
paint.setAntiAlias(真);
paint.setStyle(这个paintStyle);
paint.setStrokeWidth(此paintStrokeWidth);
油漆.固定行程盖(此.线盖);
paint.setStrokeJoin(paint.Join.MITER);//已修复
//用于文本
if(this.mode==mode.TEXT){
paint.setTypeface(此.fontFamily);
paint.setTextSize(此.fontSize);
paint.setTextAlign(this.textAlign);
油漆。设置行程宽度(0F);
}
if(this.mode==mode.橡皮擦){
//橡皮擦
setXfermode(新的PorterDuffXfermode(PorterDuff.Mode.CLEAR));
setARGB(0,0,0,0);
}否则{
//否则
paint.setColor(此.paintStrokeColor);
paint.setShadowLayer(this.blur,0F,0F,this.paintStrokeColor);
paint.setAlpha(这个是不透明度);
paint.setPathEffect(this.drawPathEffect);
}
返漆;
}
专用路径createPath(MotionEvent事件){
路径路径=新路径();
//保存以进行操作\u移动
this.startX=event.getX();
this.startY=event.getY();
path.moveTo(this.startX,this.startY);
返回路径;
}
私有void updateHistory(路径){
if(this.historyPointer==this.pathLists.size()){
this.pathLists.add(路径);
this.paintlist.add(this.createPaint());
这个.historyPointer++;
}否则{
//在撤消或重做的过程中
this.pathLists.set(this.historyPointer,path);
this.paintLists.set(this.historyPointer,this.createPaint());
这个.historyPointer++;
for(int i=this.historyPointer,size=this.paintLists.size();i=0)和&(不透明度=0){
this.blur=模糊;
}否则{
此.blur=0F;
}
}
public Paint.Cap getLineCap(){
返回此.lineCap;
}
公共无效设置linecap(Paint.Cap){
this.lineCap=cap;
}
公共路径效果getDrawPathEffect(){
回归效应;
}
公共无效setDrawPathEffect(PathEffect drawPathEffect){
这种效应
package com.android.graphics;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
public class CanvasView extends View {
public enum Mode {
DRAW,
TEXT,
ERASER;
}
public enum Drawer {
PEN,
LINE,
RECTANGLE,
CIRCLE,
ELLIPSE,
QUADRATIC_BEZIER,
QUBIC_BEZIER;
}
private Canvas canvas = null;
private Bitmap bitmap = null;
private List<Path> pathLists = new ArrayList<Path>();
private List<Paint> paintLists = new ArrayList<Paint>();
private final Paint emptyPaint = new Paint();
private int baseColor = Color.WHITE;
// for Undo, Redo
private int historyPointer = 0;
// Flags
private Mode mode = Mode.DRAW;
private Drawer drawer = Drawer.PEN;
private boolean isDown = false;
// for Paint
private Paint.Style paintStyle = Paint.Style.STROKE;
private int paintStrokeColor = Color.BLACK;
private int paintFillColor = Color.BLACK;
private float paintStrokeWidth = 3F;
private int opacity = 255;
private float blur = 0F;
private Paint.Cap lineCap = Paint.Cap.ROUND;
private PathEffect drawPathEffect = null;
// for Text
private String text = "";
private Typeface fontFamily = Typeface.DEFAULT;
private float fontSize = 32F;
private Paint.Align textAlign = Paint.Align.RIGHT; // fixed
private Paint textPaint = new Paint();
private float textX = 0F;
private float textY = 0F;
// for Drawer
private float startX = 0F;
private float startY = 0F;
private float controlX = 0F;
private float controlY = 0F;
public CanvasView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setup();
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
this.setup();
}
public CanvasView(Context context) {
super(context);
this.setup();
}
private void setup() {
this.pathLists.add(new Path());
this.paintLists.add(this.createPaint());
this.historyPointer++;
this.textPaint.setARGB(0, 255, 255, 255);
}
private Paint createPaint() {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(this.paintStyle);
paint.setStrokeWidth(this.paintStrokeWidth);
paint.setStrokeCap(this.lineCap);
paint.setStrokeJoin(Paint.Join.MITER); // fixed
// for Text
if (this.mode == Mode.TEXT) {
paint.setTypeface(this.fontFamily);
paint.setTextSize(this.fontSize);
paint.setTextAlign(this.textAlign);
paint.setStrokeWidth(0F);
}
if (this.mode == Mode.ERASER) {
// Eraser
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setARGB(0, 0, 0, 0);
} else {
// Otherwise
paint.setColor(this.paintStrokeColor);
paint.setShadowLayer(this.blur, 0F, 0F, this.paintStrokeColor);
paint.setAlpha(this.opacity);
paint.setPathEffect(this.drawPathEffect);
}
return paint;
}
private Path createPath(MotionEvent event) {
Path path = new Path();
// Save for ACTION_MOVE
this.startX = event.getX();
this.startY = event.getY();
path.moveTo(this.startX, this.startY);
return path;
}
private void updateHistory(Path path) {
if (this.historyPointer == this.pathLists.size()) {
this.pathLists.add(path);
this.paintLists.add(this.createPaint());
this.historyPointer++;
} else {
// On the way of Undo or Redo
this.pathLists.set(this.historyPointer, path);
this.paintLists.set(this.historyPointer, this.createPaint());
this.historyPointer++;
for (int i = this.historyPointer, size = this.paintLists.size(); i < size; i++) {
this.pathLists.remove(this.historyPointer);
this.paintLists.remove(this.historyPointer);
}
}
}
private Path getCurrentPath() {
return this.pathLists.get(this.historyPointer - 1);
}
private void drawText(Canvas canvas) {
if (this.text.length() <= 0) {
return;
}
if (this.mode == Mode.TEXT) {
this.textX = this.startX;
this.textY = this.startY;
this.textPaint = this.createPaint();
}
float textX = this.textX;
float textY = this.textY;
Paint paintForMeasureText = new Paint();
// Line break automatically
float textLength = paintForMeasureText.measureText(this.text);
float lengthOfChar = textLength / (float) this.text.length();
float restWidth = this.canvas.getWidth() - textX; // text-align : right
int numChars = (lengthOfChar <= 0) ? 1 : (int) Math.floor((double) (restWidth / lengthOfChar)); // The number of characters at 1 line
int modNumChars = (numChars < 1) ? 1 : numChars;
float y = textY;
for (int i = 0, len = this.text.length(); i < len; i += modNumChars) {
String substring = "";
if ((i + modNumChars) < len) {
substring = this.text.substring(i, (i + modNumChars));
} else {
substring = this.text.substring(i, len);
}
y += this.fontSize;
canvas.drawText(substring, textX, y, this.textPaint);
}
}
private void onActionDown(MotionEvent event) {
switch (this.mode) {
case DRAW:
case ERASER:
if ((this.drawer != Drawer.QUADRATIC_BEZIER) && (this.drawer != Drawer.QUBIC_BEZIER)) {
// Oherwise
this.updateHistory(this.createPath(event));
this.isDown = true;
} else {
// Bezier
if ((this.startX == 0F) && (this.startY == 0F)) {
// The 1st tap
this.updateHistory(this.createPath(event));
} else {
// The 2nd tap
this.controlX = event.getX();
this.controlY = event.getY();
this.isDown = true;
}
}
break;
case TEXT:
this.startX = event.getX();
this.startY = event.getY();
break;
default:
break;
}
}
private void onActionMove(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (this.mode) {
case DRAW:
case ERASER:
if ((this.drawer != Drawer.QUADRATIC_BEZIER) && (this.drawer != Drawer.QUBIC_BEZIER)) {
if (!isDown) {
return;
}
Path path = this.getCurrentPath();
switch (this.drawer) {
case PEN:
path.lineTo(x, y);
break;
case LINE:
path.reset();
path.moveTo(this.startX, this.startY);
path.lineTo(x, y);
break;
case RECTANGLE:
path.reset();
float left = Math.min(this.startX, x);
float right = Math.max(this.startX, x);
float top = Math.min(this.startY, y);
float bottom = Math.max(this.startY, y);
path.addRect(left, top, right, bottom, Path.Direction.CCW);
break;
case CIRCLE:
double distanceX = Math.abs((double) (this.startX - x));
double distanceY = Math.abs((double) (this.startX - y));
double radius = Math.sqrt(Math.pow(distanceX, 2.0) + Math.pow(distanceY, 2.0));
path.reset();
path.addCircle(this.startX, this.startY, (float) radius, Path.Direction.CCW);
break;
case ELLIPSE:
RectF rect = new RectF(this.startX, this.startY, x, y);
path.reset();
path.addOval(rect, Path.Direction.CCW);
break;
default:
break;
}
} else {
if (!isDown) {
return;
}
Path path = this.getCurrentPath();
path.reset();
path.moveTo(this.startX, this.startY);
path.quadTo(this.controlX, this.controlY, x, y);
}
break;
case TEXT:
this.startX = x;
this.startY = y;
break;
default:
break;
}
}
private void onActionUp(MotionEvent event) {
if (isDown) {
this.startX = 0F;
this.startY = 0F;
this.isDown = false;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Before "drawPath"
canvas.drawColor(this.baseColor);
if (this.bitmap != null) {
canvas.drawBitmap(this.bitmap, 0F, 0F, emptyPaint);
}
for (int i = 0; i < this.historyPointer; i++) {
Path path = this.pathLists.get(i);
Paint paint = this.paintLists.get(i);
canvas.drawPath(path, paint);
}
this.drawText(canvas);
this.canvas = canvas;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
this.onActionDown(event);
break;
case MotionEvent.ACTION_MOVE:
this.onActionMove(event);
break;
case MotionEvent.ACTION_UP:
this.onActionUp(event);
break;
default:
break;
}
// Re draw
this.invalidate();
return true;
}
public Mode getMode() {
return this.mode;
}
public void setMode(Mode mode) {
this.mode = mode;
}
public Drawer getDrawer() {
return this.drawer;
}
public void setDrawer(Drawer drawer) {
this.drawer = drawer;
}
public boolean canUndo() {
return this.historyPointer > 1;
}
public boolean canRedo() {
return this.historyPointer < this.pathLists.size();
}
public boolean undo() {
if (canUndo()) {
this.historyPointer--;
this.invalidate();
return true;
} else {
return false;
}
}
public boolean redo() {
if (canRedo()) {
this.historyPointer++;
this.invalidate();
return true;
} else {
return false;
}
}
public void clear() {
Path path = new Path();
path.moveTo(0F, 0F);
path.addRect(0F, 0F, 3000F, 3000F, Path.Direction.CCW);
path.close();
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
if (this.historyPointer == this.pathLists.size()) {
this.pathLists.add(path);
this.paintLists.add(paint);
this.historyPointer++;
} else {
// On the way of Undo or Redo
this.pathLists.set(this.historyPointer, path);
this.paintLists.set(this.historyPointer, paint);
this.historyPointer++;
for (int i = this.historyPointer, size = this.paintLists.size(); i < size; i++) {
this.pathLists.remove(this.historyPointer);
this.paintLists.remove(this.historyPointer);
}
}
this.text = "";
// Clear
this.invalidate();
}
public int getBaseColor() {
return this.baseColor;
}
public void setBaseColor(int color) {
this.baseColor = color;
}
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
public Paint.Style getPaintStyle() {
return this.paintStyle;
}
public void setPaintStyle(Paint.Style style) {
this.paintStyle = style;
}
public int getPaintStrokeColor() {
return this.paintStrokeColor;
}
public void setPaintStrokeColor(int color) {
this.paintStrokeColor = color;
}
public int getPaintFillColor() {
return this.paintFillColor;
}
public void setPaintFillColor(int color) {
this.paintFillColor = color;
}
public float getPaintStrokeWidth() {
return this.paintStrokeWidth;
}
public void setPaintStrokeWidth(float width) {
if (width >= 0) {
this.paintStrokeWidth = width;
} else {
this.paintStrokeWidth = 3F;
}
}
public int getOpacity() {
return this.opacity;
}
public void setOpacity(int opacity) {
if ((opacity >= 0) && (opacity <= 255)) {
this.opacity = opacity;
} else {
this.opacity = 255;
}
}
public float getBlur() {
return this.blur;
}
public void setBlur(float blur) {
if (blur >= 0) {
this.blur = blur;
} else {
this.blur = 0F;
}
}
public Paint.Cap getLineCap() {
return this.lineCap;
}
public void setLineCap(Paint.Cap cap) {
this.lineCap = cap;
}
public PathEffect getDrawPathEffect() {
return drawPathEffect;
}
public void setDrawPathEffect(PathEffect drawPathEffect) {
this.drawPathEffect = drawPathEffect;
}
public float getFontSize() {
return this.fontSize;
}
public void setFontSize(float size) {
if (size >= 0F) {
this.fontSize = size;
} else {
this.fontSize = 32F;
}
}
public Typeface getFontFamily() {
return this.fontFamily;
}
public void setFontFamily(Typeface face) {
this.fontFamily = face;
}
public Bitmap getBitmap() {
this.setDrawingCacheEnabled(false);
this.setDrawingCacheEnabled(true);
return Bitmap.createBitmap(this.getDrawingCache());
}
public Bitmap getScaleBitmap(int w, int h) {
this.setDrawingCacheEnabled(false);
this.setDrawingCacheEnabled(true);
return Bitmap.createScaledBitmap(this.getDrawingCache(), w, h, true);
}
public void drawBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
this.invalidate();
}
public void drawBitmap(byte[] byteArray) {
this.drawBitmap(BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length));
}
public static byte[] getBitmapAsByteArray(Bitmap bitmap, CompressFormat format, int quality) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(format, quality, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
public byte[] getBitmapAsByteArray(CompressFormat format, int quality) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
this.getBitmap().compress(format, quality, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
public byte[] getBitmapAsByteArray() {
return this.getBitmapAsByteArray(CompressFormat.PNG, 100);
}
}