2011-06-20 38 views
5

我正在使用Android的定製版本FingerPaint,並具有其他一些功能,如插入圖像和移動它們。我決定實施撤消&重做,因爲它會讓生活變得更輕鬆。爲了實現它,我最終決定使用一個堆棧,在這裏我推動視圖的繪圖緩存,並且每當我想要返回到先前的狀態時從哪裏推內容。因此,使用FingerPaint作爲基礎,我有以下幾點:只有觸摸起來的那一刻之後在Android的畫布中撤消和重做

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

堆棧正在更新,因爲我還是搞清楚如何解決這個問題。當我想申請重做時,我做了以下操作:

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

到目前爲止,應用程序顯示屏幕的原始狀態沒有變化。我也試圖用白色背景畫它來重置它,但這種方法也不起作用。

有關如何解決此問題的任何想法或建議?我會很感激:)

問候

+0

'indexOfUndoRedo'如何初始化? – Rom1

+0

我將它初始化爲-1(所以,當我添加第一個元素時,值將爲0)。但仍然無法正常工作 – kikoso

回答

9

試試下面的代碼繪製查看:

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

,並畫出下面活動佈局代碼:

<?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> 

,並繪製下面的代碼活動課:

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

} 

這是一個在Android中使用撤銷和重做操作的示例繪畫應用程序,它對我來說非常適合!

+0

+1不錯的一個只是改變這一行mPaint.setColor(0xFFFFFFFF);''mPaint.setColor(0xff00ff00);'工作很好因爲'0xFFFFFFFF'已經是白色已經背景顏色是白色所以爲什麼不顯示在繪製路徑..... – NagarjunaReddy

+1

它不能完美工作,因爲在第一次點擊撤消按鈕時它不起作用,並在第二次點擊它的作品。 – anddev

+1

@anddev看到這個帖子它的工作正常http://stackoverflow.com/questions/11114625/android-canvas-redo-and-undo-operation – Dinesh

2

這是工作代碼。我在我自己的應用上測試它,它工作得很好,可能對別人有幫助。請對此發表評論。

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

}