Ich habe diesen Code aus einer Antwort in einer der Fragen, die Frage, wie in Android zu zeichnen, aber dann bei der Verwendung und Testen in meiner App fand ich heraus, dass es nicht effizient ist, wenn große Dinge oder viele Wege zeichnen. Das Problem kommt vom Code innerhalb onDraw
, weil jedes invalidate()
genannt wird, das eine Schleife enthält, die alle paths
wieder zum canvas
zeichnet, und indem es mehr Wege ihm hinzufügt, wird es sehr sehr langsam. HierAndroid Drawing View ist sehr langsam
ist die Klasse:
public class DrawingView extends View implements OnTouchListener {
private Canvas m_Canvas;
private Path m_Path;
private Paint m_Paint;
ArrayList<Pair<Path, Paint>> paths = new ArrayList<Pair<Path, Paint>>();
ArrayList<Pair<Path, Paint>> undonePaths = new ArrayList<Pair<Path, Paint>>();
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
public static boolean isEraserActive = false;
private int color = Color.BLACK;
private int stroke = 6;
public DrawingView(Context context, AttributeSet attr) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
setBackgroundColor(Color.WHITE);
this.setOnTouchListener(this);
onCanvasInitialization();
}
public void onCanvasInitialization() {
m_Paint = new Paint();
m_Paint.setAntiAlias(true);
m_Paint.setDither(true);
m_Paint.setColor(Color.parseColor("#000000"));
m_Paint.setStyle(Paint.Style.STROKE);
m_Paint.setStrokeJoin(Paint.Join.ROUND);
m_Paint.setStrokeCap(Paint.Cap.ROUND);
m_Paint.setStrokeWidth(2);
m_Canvas = new Canvas();
m_Path = new Path();
Paint newPaint = new Paint(m_Paint);
paths.add(new Pair<Path, Paint>(m_Path, newPaint));
}
@Override
public void setBackground(Drawable background) {
mBackground = background;
super.setBackground(background);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
public boolean onTouch(View arg0, MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
for (Pair<Path, Paint> p : paths) {
canvas.drawPath(p.first, p.second);
}
}
private void touch_start(float x, float y) {
if (isEraserActive) {
m_Paint.setColor(Color.WHITE);
m_Paint.setStrokeWidth(50);
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
paths.add(new Pair<Path, Paint>(m_Path, newPaint));
} else {
m_Paint.setColor(color);
m_Paint.setStrokeWidth(stroke);
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
paths.add(new Pair<Path, Paint>(m_Path, newPaint));
}
m_Path.reset();
m_Path.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
m_Path.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
m_Path.lineTo(mX, mY);
// commit the path to our offscreen
m_Canvas.drawPath(m_Path, m_Paint);
// kill this so we don't double draw
m_Path = new Path();
Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
paths.add(new Pair<Path, Paint>(m_Path, newPaint));
}
public void onClickUndo() {
if (!paths.isEmpty()) {//paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
undo = true;
invalidate();
}
}
public void onClickRedo() {
if (!undonePaths.isEmpty()){//undonePaths.size() > 0) {
paths.add(undonePaths.remove(undonePaths.size() - 1));
undo = true;
invalidate();
}
}}
Aber ich im Internet gesucht wieder einen besseren Weg zum Zeichnen zu finden, so fand ich folgende:
1 Fügen Sie den folgenden an den Konstruktor:
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
2 Aufschalten OnSizeChanged mit dem folgenden Code:
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
m_Canvas = new Canvas(mBitmap);
}
3 Setzen Sie diese in OnDraw:
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
if (!paths.isEmpty())
canvas.drawPath(paths.get(paths.size() - 1).first, paths.get(paths.size() - 1).second);
}
Dieser Ansatz funktioniert und es nicht verlangsamt die Ansicht, aber das Problem mit diesem Ansatz ist, dass ich nicht rückgängig machen kann und Redo-Funktionen.
Ich habe viele verschiedene Dinge ausprobiert, um das Rückgängigmachen und Wiederholen mit dem zweiten Ansatz durchzuführen, aber ich konnte es nicht tun. Also, was ich hier frage, ist eines von drei Dingen: 1. Eine Möglichkeit, rückgängig zu machen und wiederholen mit dem zweiten Ansatz 2. Ein anderer Ansatz, der es ermöglicht, rückgängig machen und wiederholen 3. Eine ganz neue Klasse, die hat alles bereits erledigt, wie eine Open-Source-Bibliothek oder so.
Bitte helfen Sie, wenn Sie können. Dank
EDIT 1
OK, so beschränken ich es so weit nach unten und dann kann ich nichts mehr, ich habe jetzt über 8 Stunden versucht. Es funktioniert bis zum Rückgängigmachen (Sie können so viele Pfade rückgängig machen, wie Sie möchten), und wenn Sie dann erneut zeichnen, verschwinden alle verbleibenden Pfade, ich weiß nicht, was es dazu bringt.
@Override
protected void onDraw(Canvas canvas) {
if (mBitmap != null)
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
if (!paths.isEmpty() && !undo)
canvas.drawPath(paths.get(paths.size() - 1).first, paths.get(paths.size() - 1).second);
if (undo) {
setBackground(mBackground);
for (Pair<Path, Paint> p : paths)
canvas.drawPath(p.first, p.second);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
m_Canvas = new Canvas(mBitmap);
undo = false;
}
}
so im Grunde, was ich ist, den ersten Ansatz zunächst verwenden hat (vor Undo genannt wird), dann, wenn Undo geklickt wird, wird undo
auf true
und der Code unter if (undo)
ausgeführt, der tatsächlich der erste Ansatz ist (Berechnung aller Pfade erneut), dann zeichne ich das Ergebnis der Berechnung aller Pfade wieder in mBitmap
, also wenn immer wieder die aufgerufen wird, zieht es sich an, aber dieser Teil muss noch funktionieren, ich hoffe jemand kann mit diesem Teil helfen.
Ich habe Angst zu sagen, dass, wenn Sie so viele Pfade zeichnen, dann Ihre Ansicht wird langsam sein. Sie sollten versuchen, eine Methode zu finden, bei der ein wirklich langer Pfad gezeichnet wird. – jcw
Wenn Sie die neuen Pfade immer auf die alten zeichnen, können Sie beide Methoden kombinieren, wobei alle außer den letzten n Pfaden in die Bitmap eingefügt werden, und das letzte n mit der vorherigen Methode zeichnen. Dann können Sie diese letzten mindestens auf rückgängig machen –