2011-06-20 35 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; 
    } 

}