2011-06-20 14 views
5

Używam niestandardowej wersji FingerPaint dla Androida z kilkoma innymi funkcjami, takimi jak wstawianie i przenoszenie obrazów. Postanowiłem wprowadzić Undo & Redo, ponieważ ułatwi to życie. Aby go zaimplementować, w końcu zdecydowałem się użyć Stack, w którym wypycham pamięć podręczną rysunku i skąd wysyłam treść za każdym razem, gdy chcę wrócić do poprzedniego stanu. Tak więc, stosując fingerpaint jako podstawa, mam następujące:Cofanie i ponawianie w Canvas dla Androida

private void touch_up() { 
    mPath.lineTo(mX, mY); 
    // commit the path to our offscreen 
    mCanvas.drawPath(mPath, mPaint); 
    // I enable the set drawing cache...  
    myView.setDrawingCacheEnabled(true); 
    // ... and I add the cache to the stack 
    undoStack.add(myView.getDrawingCache()); 
    indexOfUndoRedo++; 
    // kill this so we don't double draw 
    mPath.reset(); 
} 

Stos jest aktualizowany tylko po kontakcie się w tej chwili, ponieważ jestem jeszcze dowiedzieć się, jak rozwiązać ten problem. Kiedy chcesz zastosować redo, I wykonaj następujące czynności:

private void undo() { 
    myView = new MyView(getActivity()); 
    myView.setBackgroundDrawable(new BitmapDrawable(undoStack.get(indexOfUndoRedo))); 
    indexOfUndoRedo--; 
    myView.invalidate(); 
} 

Dotychczas aplikacja pokazuje stan pierwotny ekranu bez zmian. Próbowałem też pomalować go białym tłem, aby go zresetować, ale to podejście też nie działa.

Każdy pomysł lub sugestia, jak rozwiązać ten problem? Byłbym bardzo wdzięczny :)

Pozdrowienia

+0

W jaki sposób zainicjowano "indexOfUndoRedo"? – Rom1

+0

I zainicjować go do -1 (więc, gdy dodaję pierwszy element, wartość będzie 0). Ale wciąż nie działa – kikoso

Odpowiedz

9

Spróbuj poniżej kod Draw Widok:

package com.draw; 
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; 
import android.widget.ImageView; 

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) {    

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

i Draw aktywny kod układu poniżej:

<?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" > 
<FrameLayout android:id="@+id/main_frame" 
    android:layout_width="fill_parent" android:layout_height="250dp"> 

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

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

</LinearLayout> 

i Draw Klasa aktywności poniżej kodu:

package com.draw; 

import android.app.Activity; 
import android.os.Bundle; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.FrameLayout; 
import android.widget.ImageButton; 
import android.widget.ImageView; 
import android.widget.LinearLayout; 
import android.widget.Toast; 

public class Draw extends Activity { 
    ImageView iv1; 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     final DrawView drawView = new DrawView(this); 
     setContentView(R.layout.main); 
     FrameLayout frm_layout=(FrameLayout) findViewById(R.id.main_frame); 
     frm_layout.addView(drawView); 
     Button btn_undo=(Button) findViewById(R.id.button1); 
     btn_undo.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       // TODO Auto-generated method stub 
       drawView.onClickUndo(); 
      } 
     }); 

     Button btn_redo=(Button) findViewById(R.id.button2); 
     btn_redo.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       // TODO Auto-generated method stub 
       drawView.onClickRedo(); 
      } 
     }); 
    } 

} 

To przykładowa aplikacja do malowania z operacjami cofania i ponawiania w systemie Android, działa doskonale dla mnie!

+0

+1 ładny po prostu zmienić ten wiersz 'mPaint.setColor (0xFFFFFFFF);' na 'mPaint.setColor (0xff00FF00);' działa dobrze ponieważ '0xFFFFFFFF' jest biały kolor już kolor tła jest biały dlatego nie pokazuj na ścieżce rysowania ..... – NagarjunaReddy

+1

Nie działa idealnie, ponieważ przy pierwszym kliknięciu przycisku cofania nie działa, a po drugim kliknięciu działa. – anddev

+1

@anddev zobacz ten post działa poprawnie http://stackoverflow.com/questions/11114625/android-canvas-redo-and-undo-operation – Dinesh

2

To działa kod. Testuję go na własnej aplikacji i działa bardzo dobrze, może być pomocny dla innych. Proszę o komentarz.

public class Main extends Activity implements OnColorChangedListener { 
    // public static int selectedColor = Color.BLACK; 
    public static ArrayList<Path> mMaindialog; 
    // private ArrayList<Path> undonePaths; 
    // public int selectedcolor; 
    private static final String COLOR_PREFERENCE_KEY = "color"; 
    private FrameLayout relativelayout; 
    static String sdpath, location; 
    Boolean i; 
    // Instance variables 
    private Bitmap mBitmap = null; 
    Bitmap bitmap; 
    private Paint mPaint, mBitmapPaint, mPaint1; 
    private MyView mView; 
    ImageView idd; 
    // private Path mPath; 
    int slll = Color.BLACK; 
    Bitmap map = ListView5.bMap; 
    private Button ClearPaint, Colorpaint; 
    Ghostdatabase gost; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     idd = (ImageView) findViewById(R.id.imageView1); 
     relativelayout = (FrameLayout) findViewById(R.id.frameLayout); 

     DisplayMetrics metrics = getBaseContext().getResources() 
       .getDisplayMetrics(); 
     int w = metrics.widthPixels; 
     int h = metrics.heightPixels; 

     System.out.println(" width " + w); 
     System.out.println(" height " + h); 

     mView = new MyView(this, w, h); 
     mView.setDrawingCacheEnabled(true); 

     mPaint = new Paint(); 
     mPaint.setAntiAlias(true); 
     mPaint.setDither(true); 
     mPaint.setColor(Color.BLACK); 
     mPaint.setStyle(Paint.Style.STROKE); 
     mPaint.setStrokeJoin(Paint.Join.ROUND); 
     mPaint.setStrokeCap(Paint.Cap.ROUND); 
     mPaint.setStrokeWidth(4); 

     ClearPaint = (Button) findViewById(R.id.ne); 
     ClearPaint.setOnClickListener(new OnClickListener() { 

      public void onClick(View v) { 
       // mBitmap.eraseColor(Color.TRANSPARENT); 
       // mPath.reset(); 
       // mView.invalidate(); 

       mView.onClickUndo(); 

      } 
     }); 
     Button save22 = (Button) findViewById(R.id.save); 
     save22.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       // TODO Auto-generated method stub 
       File cacheDir; 
       Toast.makeText(Main.this, "Photo", 500).show(); 
       Bitmap icon; 
       relativelayout.setDrawingCacheEnabled(true); 

       icon = Bitmap.createBitmap(relativelayout.getDrawingCache()); 
       Bitmap bitmap = icon; 
       relativelayout.setDrawingCacheEnabled(false); 
       // File mFile1 = Environment.getExternalStorageDirectory(); 
       Date d = new Date(); 
       String fileName = d.getTime() + "mg1.jpg"; 

       File storagePath = (Environment.getExternalStorageDirectory()); 
       File dest = new File(storagePath + "/CityAppImages"); 

       if (!dest.exists()) { 
        dest.mkdirs(); 

       } 

       File mFile2 = new File(dest, fileName); 
       sdpath = mFile2.getAbsolutePath(); 

       Log.d("qqqqqqqqqqqqqqqqqqqqqqq", "zzzzzzzz" + sdpath); 
       try { 
        FileOutputStream outStream; 

        outStream = new FileOutputStream(mFile2); 

        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream); 

        outStream.flush(); 

        outStream.close(); 
        Toast.makeText(Main.this, "Photo Saved Sucessfully", 500) 
          .show(); 
       } catch (FileNotFoundException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } catch (IOException e) { 

        // TODO Auto-generated catch block 
        e.printStackTrace(); 
        Toast.makeText(Main.this, "Photo Not Saved Sucessfully", 
          500).show(); 
       } 

       gost = new Ghostdatabase(Main.this); 
       gost.open(); 

       gost.insertTitle(sdpath); 
      } 
     }); 

     Button view = (Button) findViewById(R.id.listtt); 
     view.setOnClickListener(new OnClickListener() { 

      public void onClick(View v) { 

       Intent ii = new Intent(Main.this, ListView5.class); 
       startActivity(ii); 

      } 
     }); 

     Button Colorpaint = (Button) findViewById(R.id.Color); 
     Colorpaint.setOnClickListener(new OnClickListener() { 

      public void onClick(View v) { 
       int color = PreferenceManager.getDefaultSharedPreferences(
         Main.this).getInt(COLOR_PREFERENCE_KEY, Color.WHITE); 
       // int _color = R.color.red; 
       new ColorPickerDialog(v.getContext(), 
         new OnColorChangedListener() { 

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

           slll = color; 

           Log.i("TAG", "mpaint one" + mPaint); 
          } 
         }, mPaint.getColor()).show(); 
       Log.i("TAG", "mpaint two" + mPaint); 
      } 
     }); 
     relativelayout.addView(mView); 
    } 

    // //////////******************* Pinting view 
    // *******************/////////////////// 

    public class MyView extends View implements OnTouchListener { 
     private Map<Path, Integer> colorsMap = new HashMap<Path, Integer>(); 
     private ArrayList<Path> mMaindialog = new ArrayList<Path>(); 
     private ArrayList<Path> undonePaths = new ArrayList<Path>(); 
     int colorPicked = slll; 
     // Paint mPaint1; 

     private Canvas mCanvas; 
     private Path mPath; 

     public MyView(Context c, int w, int h) { 
      super(c); 
      if (GlobalVariable.impath == 1) { 
       Log.d("", "111111" + GlobalVariable.impath); 
       System.out.println(GlobalVariable.impath); 
       Intent ii = getIntent(); 
       location = ii.getStringExtra("IMAGE"); 
       // bitmap.recycle(); 
       Log.d("", "location" + location); 
       bitmap = BitmapFactory.decodeFile(location); 
       mBitmap = Bitmap.createScaledBitmap(bitmap, 300, 300, false); 
       Log.d("hhhhhhhhhhhhhhhssssssss", "mBitmap" + mBitmap); 
       // mBitmap = Bitmap.createBitmap(100, 100, 
       // Bitmap.Config.ARGB_8888); 
       // idd.setImageBitmap(mBitmap); 
       Log.d("hhhhhhhhhhhhhhhssssssss", "GlobalVariable.impath" 
         + GlobalVariable.impath); 
      } else if (GlobalVariable.impath == 2) { 
       // bitmap.recycle(); 
       Log.d("", "22222222222222222222222" + GlobalVariable.impath); 
       bitmap = BitmapFactory.decodeResource(getResources(), 
         R.drawable.base); 
       mBitmap = Bitmap.createScaledBitmap(bitmap, 100, 100, false); 
       // mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
       Log.d("hhhhhhhhhhhhhhhssssssss1111111", "mBitmap" + mBitmap); 
      } 

      // 
      mCanvas = new Canvas(mBitmap); 
      mPath = new Path(); 

     } 

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

     } 

     @Override 
     protected void onDraw(Canvas canvas) { 

      canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); 

      for (Path p : mMaindialog) { 
       mPaint.setColor(colorsMap.get(p)); 
       canvas.drawPath(p, mPaint); 
      } 
      mPaint.setColor(slll); 
      canvas.drawPath(mPath, mPaint); 
     } 

     // //////************touching evants for painting**************/////// 
     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; 
      undonePaths.clear(); 
     } 

     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(); 
      mPath.reset(); 
      mMaindialog.add(mPath); 
     } 

     @Override 
     public boolean onTouchEvent(MotionEvent event) { 
      float x = event.getX(); 
      float y = event.getY(); 
      switch (event.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
       // touch_start(x, y); 
       // invalidate(); 
       undonePaths.clear(); 
       mPath.reset(); 
       mPath.moveTo(x, y); 
       mX = x; 
       mY = y; 
       invalidate(); 
       break; 
      case MotionEvent.ACTION_MOVE: 
       // touch_move(x, y); 
       // invalidate(); 
       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; 
       } 
       invalidate(); 
       break; 
      case MotionEvent.ACTION_UP: 
       // touch_up(); 
       // invalidate(); 
       mPath.lineTo(mX, mY); 
       mMaindialog.add(mPath); 
       colorsMap.put(mPath, slll); 
       mPath = new Path(); 
       mPath.reset(); 
       invalidate(); 
       break; 
      } 
      return true; 
     } // end of touch events for image 

     private Paint createPen(int colorPicked) { 
      // TODO Auto-generated method stub 
      mPaint1 = new Paint(); 
      mPaint1.setColor(colorPicked); 
      mPaint1.setAntiAlias(true); 
      mPaint1.setDither(true); 
      mPaint1.setStyle(Paint.Style.STROKE); 
      mPaint1.setStrokeJoin(Paint.Join.ROUND); 
      mPaint1.setStrokeCap(Paint.Cap.ROUND); 
      // mPaint1.setStrokeWidth(3); 
      return mPaint1; 
     } 

     public void onClickRedo() { 
      if (undonePaths.size() > 0) { 
       mMaindialog.add(undonePaths.remove(undonePaths.size() - 1)); 
       mView.invalidate(); 

      } else { 

      } 
      // toast the user 
     } 

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

      else { 

      } 
     } 

     @Override 
     public boolean onTouch(View arg0, MotionEvent arg1) { 
      // TODO Auto-generated method stub 
      return false; 
     } 
    }// end MyView 

    @Override 
    public void colorChanged(int color) { 
     // TODO Auto-generated method stub 
     PreferenceManager.getDefaultSharedPreferences(this).edit() 
       .putInt(COLOR_PREFERENCE_KEY, color).commit(); 
     slll = color; 
    } 

}