Вопрос по android – Android Canvas Redo и отмена операции

19

я работаю над чертежом project.my код мудрый работает отлично, но операция холостого хода и отмены не работает идеально. операция отмены не работает идеально и операции повторного выполнения не работают отлично. моя операция отмены удаляет пути из массива путей и сохраняет в недопустимых списках массивов и повторов операция удаляет последний элемент из списка недопутанных файлов и сохраняет его в пути.

Вот мой код:

import java.util.ArrayList;
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.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class DrawView extends View implements OnTouchListener {
    private Canvas  mCanvas;
    private Path    mPath;
    private Paint       mPaint;   
    private ArrayList<Path> paths = new ArrayList<Path>();
    private ArrayList<Path> undonePaths = new ArrayList<Path>(); 

    private Bitmap im;
    public DrawView(Context context) 
    {
        super(context);
        setFocusable(true);
        setFocusableInTouchMode(true);      
        this.setOnTouchListener(this);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(0xFFFFFFFF);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(6);
        mCanvas = new Canvas();
        mPath = new Path();
        paths.add(mPath);

        im=BitmapFactory.decodeResource(context.getResources(),R.drawable.ic_launcher);


    }               
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            //mPath = new Path();
            //canvas.drawPath(mPath, mPaint);
            for (Path p : paths){
                canvas.drawPath(p, mPaint);
            }
        }

        private float mX, mY;
        private static final float TOUCH_TOLERANCE = 4;

        private void touch_start(float x, float y) {
            mPath.reset();
            mPath.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) {
                mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
                mX = x;
                mY = y;
            }
        }
        private void touch_up() {
            mPath.lineTo(mX, mY);
            // commit the path to our offscreen
            mCanvas.drawPath(mPath, mPaint);
            // kill this so we don't double draw            
            mPath = new Path();
            paths.add(mPath);
        }

        public void onClickUndo () { 
            if (paths.size()>0) 
            { 
               undonePaths.add(paths.remove(paths.size()-1));
               invalidate();
             }
            else
            {

            }
             //toast the user 
        }

        public void onClickRedo (){
           if (undonePaths.size()>0) 
           { 
               paths.add(undonePaths.remove(undonePaths.size()-1)); 
               invalidate();
           } 
           else 
           {

           }
             //toast the user 
        }

    @Override
    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;
    }
}

этот рисунок кода работает отлично и не работает идеально отменить и повторить операцию.

что не так в моем коде!

Как решить эту проблему, любой может помочь мне с благодарностью.

Вот мой исходный код

http://www.4shared.com/rar/8PQQEZdH/test_draw.html

Спасибо...

UPDATED:

finally my problem was solved here's my drawing class :

import java.util.ArrayList;
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.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class DrawView extends View implements OnTouchListener {
    private Canvas  mCanvas;
    private Path    mPath;
    private Paint       mPaint;   
    private ArrayList<Path> paths = new ArrayList<Path>();
    private ArrayList<Path> undonePaths = new ArrayList<Path>(); 

    private Bitmap im;
    public DrawView(Context context) 
    {
        super(context);
        setFocusable(true);
        setFocusableInTouchMode(true);      
        this.setOnTouchListener(this);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(0xFFFFFFFF);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(6);
        mCanvas = new Canvas();
        mPath = new Path();

        im=BitmapFactory.decodeResource(context.getResources(),R.drawable.ic_launcher);


    }               
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            //mPath = new Path();
            //canvas.drawPath(mPath, mPaint);
            for (Path p : paths){
                canvas.drawPath(p, mPaint);
            }
            canvas.drawPath(mPath, mPaint);
        }

        private float mX, mY;
        private static final float TOUCH_TOLERANCE = 4;

        private void touch_start(float x, float y) {
            undonePaths.clear();
            mPath.reset();
            mPath.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) {
                mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
                mX = x;
                mY = y;
            }
        }
        private void touch_up() {
            mPath.lineTo(mX, mY);
            // commit the path to our offscreen
            mCanvas.drawPath(mPath, mPaint);
            // kill this so we don't double draw
            paths.add(mPath);
            mPath = new Path();            

        }

        public void onClickUndo () { 
            if (paths.size()>0) 
            { 
               undonePaths.add(paths.remove(paths.size()-1));
               invalidate();
             }
            else
            {

            }
             //toast the user 
        }

        public void onClickRedo (){
           if (undonePaths.size()>0) 
           { 
               paths.add(undonePaths.remove(undonePaths.size()-1)); 
               invalidate();
           } 
           else 
           {

           }
             //toast the user 
        }

    @Override
    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;
    }
}

That's code is working perfectly...!

Этот код работает хорошо. Но когда я рисую первую линию, затем корректирую цвет, а затем рисую еще одну линию, первая линия также сразу же превратится в новый цвет. Пожалуйста, помогите. Jason
@ Ник .... я обновляю свой вопрос, найдите ссылку на исходный код Dinesh
Можете ли вы вставить полный исходный код? Nikhil
Пожалуйста, поделитесь этим с общественностью, попросите меня сначала зарегистрироваться .. Nikhil
Как бы вы определилиnot working perfectly? Что именно происходит, что не желательно? Kazekage Gaara

Ваш Ответ

3   ответа
13

By adding your empty Path to paths as soon as you make it, you're going to have a problem as soon as you undo: you're popping that empty Path first, making the first undo not seem to work. Then if you draw into that Path, it's not added to paths. The solution is to add the completed Path to paths in touch_up() before creating a new one.

То есть удалить

paths.add(mPath);

от конструктора, и вtouch_up(), менять

mPath = new Path();
paths.add(mPath);

в

paths.add(mPath);
mPath = new Path();

Вы также хотите добавить

canvas.drawPath(mPath, mPaint);

после вашегоfor зациклитьсяonDraw() чтобы нарисовать незавершенноеPath.

You're not emptying undonePaths when the user starts drawing again.
@DarshanComputing, как реализовать функцию стирания с операцией отмены?
@HeroVsZero Я рад, что это сработало (не забыл проголосовать и выбрать мой ответ, так как он сработал для вас). Что касается задержки, вам нужно будет подвести итогиPath сcanvas.drawPath(mPath, mPaint); вonDraw() (послеfor петля). Я обновил свой ответ, чтобы отразить это.
да, вы решили мою проблему. но рисование с задержкой для пути, как решить эту проблему? Dinesh
Примите +1, Спасибо за ответ, работающий как чары! Dinesh
@DhavalKhant Если «стереть» Вы имеете в виду Path с тем же цветом, что и цвет фона, ничего не меняется. Так что, возможно, вы имеете в виду очистку холста? Я реализую отмену / повтор с помощью android.graphics.Pictures, а не android.graphics.Paths, что решает эту проблему. Это можно сделать с помощью Paths, возможно, используя пустой Path для представления прозрачного Canvas. Или вы можете использовать Список некоторого пользовательского объекта, который ссылается либо на Path, либо на Canvas clear. Есть много вариантов.
1
Problem

как вы закончите его рисовать, что не дает пользователю понять, что он рисует

Solution
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

   for (Path p : paths){
        canvas.drawPath(p, mPaint);
    }

    //Draw path along with the finger
    canvas.drawPath(mPath, mPaint);
}

добавлятьcanvas.drawPath(mPath,mPaint) вonDraw() таким образом, у пользователя появляется ощущение, что он действительно рисует на холсте.

Это опубликовано как ответ, но не затрагивает какую-либо часть вопроса. (И принятый ответ уже решает эту проблему.)
5

package com.testpath;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.LinearLayout;

public class TesUndoPaintActivity extends Activity {
    /** Called when the activity is first created. */
    LinearLayout linearLayout2;
    private ArrayList<Path> undonePaths = new ArrayList<Path>();
    private ArrayList<Path> paths = new ArrayList<Path>();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        linearLayout2 = (LinearLayout) findViewById(R.id.linearLayout2);
        final DrawingPanel dp = new DrawingPanel(this);
        linearLayout2.addView(dp);
        ((Button) findViewById(R.id.button1))
                .setOnClickListener(new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        if (paths.size() > 0) {
                            undonePaths.add(paths
                                    .remove(paths.size() - 1));
                            dp.invalidate();
                        }
                    }
                });
        ((Button) findViewById(R.id.button2))
        .setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                 if (undonePaths.size()>0) { 
                       paths.add(undonePaths.remove(undonePaths.size()-1));
                       dp.invalidate();
                   } 
            }
        });
    }

    public class DrawingPanel extends View implements OnTouchListener {

        private Canvas mCanvas;
        private Path mPath;
        private Paint mPaint, circlePaint, outercirclePaint;

        // private ArrayList<Path> undonePaths = new ArrayList<Path>();
        private float xleft, xright, xtop, xbottom;

        public DrawingPanel(Context context) {
            super(context);
            setFocusable(true);
            setFocusableInTouchMode(true);

            this.setOnTouchListener(this);

            circlePaint = new Paint();
            mPaint = new Paint();
            outercirclePaint = new Paint();
            outercirclePaint.setAntiAlias(true);
            circlePaint.setAntiAlias(true);
            mPaint.setAntiAlias(true);
            mPaint.setColor(0xFFFFFFFF);
            outercirclePaint.setColor(0x44FFFFFF);
            circlePaint.setColor(0xAADD5522);
            outercirclePaint.setStyle(Paint.Style.STROKE);
            circlePaint.setStyle(Paint.Style.FILL);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(6);
            outercirclePaint.setStrokeWidth(6);
            mCanvas = new Canvas();
            mPath = new Path();
            paths.add(mPath);
        }

        public void colorChanged(int color) {
            mPaint.setColor(color);
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
        }

        @Override
        protected void onDraw(Canvas canvas) {

            for (Path p : paths) {
                canvas.drawPath(p, mPaint);
            }

        }

        private float mX, mY;
        private static final float TOUCH_TOLERANCE = 0;

        private void touch_start(float x, float y) {
            mPath.reset();
            mPath.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) {
                mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
                mX = x;
                mY = y;
            }
        }

        private void touch_up() {
            mPath.lineTo(mX, mY);
            // commit the path to our offscreen
            mCanvas.drawPath(mPath, mPaint);
            // kill this so we don't double draw
            mPath = new Path();
            paths.add(mPath);
        }

        @Override
        public boolean onTouch(View arg0, MotionEvent event) {
            float x = event.getX();
            float y = event.getY();

            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // if (x <= cx+circ,leRadius+5 && x>= cx-circleRadius-5) {
                // if (y<= cy+circleRadius+5 && cy>= cy-circleRadius-5){
                // paths.clear();
                // return true;
                // }
                // }
                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;
        }
    }
}

И ниже XML-файл.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Undo" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Redo" />

    </LinearLayout>


    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

    </LinearLayout>

</LinearLayout>

Пожалуйста, проверь это.

+1, Спасибо за ваш эффект, снимаю шляпу!. Извините, ваш код всегда работает, но возникли проблемы, я нашел ответ от @Darshan Computing Dinesh
ваш код работает отлично, но, одна проблема отменить кнопку первый раз нажмите не отменить рисунок, как решить эту проблему? Dinesh

Похожие вопросы