2013-06-19 8 views
8

Sto creando un'app di disegno che utilizza la classe DrawingSurfaceView di seguito. In quella classe ho un Paint Called eraserPaint che l'utente può attivare e disattivare .. Quando su quella vernice si suppone di cancellare ciò che è sempre sul suo percorso. ma invece il suo solo tracciando una linea nera ..Provare a creare una gomma da cancellare per tela

quando salvo la tela come un PNG trasparente la gomma è corretto, ma sullo schermo si vede nero ..

Schermata dal telefono di EraserPaint usato per scrivere "Erik" sul blob

enter image description here

salvato da PNG dalla tela enter image description here

eraserPaint assomiglia a questo:

eraserPaint = new Paint(); 
     eraserPaint.setAlpha(0); 
     eraserPaint.setColor(Color.TRANSPARENT); 
     eraserPaint.setStrokeWidth(60); 
     eraserPaint.setStyle(Style.STROKE); 
     eraserPaint.setMaskFilter(null); 
     eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 
     eraserPaint.setAntiAlias(true); 

classe TUTTO

 public KNDrawingSurfaceView(Context c, float width, float height, KNSketchBookActivity parent) { 

     super(c); 

     myWidth = width; 
     myHeight = height; 

     mBitmap = Bitmap.createBitmap((int) myWidth, (int) myHeight, Bitmap.Config.ARGB_8888); 
     mCanvas = new Canvas(mBitmap); 

     _parent = parent; 


     mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f); 


     tile = new Paint(); 

     tileImage = BitmapFactory.decodeResource(getResources(), R.drawable.checkerpattern); 
     shader = new BitmapShader(tileImage, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); 
     tile.setShader(shader); 


     mPath = new Path(); 
     eraserPaint = new Paint(); 
     eraserPaint.setAlpha(0x00); 
     eraserPaint.setColor(Color.TRANSPARENT); 
     eraserPaint.setStrokeWidth(60); 
     eraserPaint.setStyle(Style.STROKE); 
     //eraserPaint.setMaskFilter(null); 
     eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 
     eraserPaint.setAntiAlias(true); 

     mBitmapPaint = new Paint(Paint.DITHER_FLAG); 



     mCanvas.drawRect(0, 0, myWidth, myHeight, tile); 

     mCanvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); 
     mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); 
    } 

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

     super.onSizeChanged(w, h, oldw, oldh); 


    } 

    @Override 
    protected void onDraw(Canvas canvas) { 

     if (!_parent.isDrawerOpen()&&mPaint!=null) { 
      Log.v("onDraw:", "curent paths size:" + paths.size()); 

      //mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); 
      //canvas.drawPath(mPath, mPaint); 
      for (int i=0;i< paths.size();i++) { 
       tempPaint = paints.get(i); 
       eraserPaint.setStrokeWidth(tempPaint.getStrokeWidth()); 
       if(fills.get(i)){ 
        tempPaint.setStyle(Style.FILL_AND_STROKE); 
        eraserPaint.setStyle(Style.FILL_AND_STROKE); 
       }else{ 
        tempPaint.setStyle(Style.STROKE); 
        eraserPaint.setStyle(Style.STROKE); 
       } 
       if(erasers.get(i)){ 
        //tempPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 
        canvas.drawPath(paths.get(i), eraserPaint); 
       }else{ 
        //tempPaint.setXfermode(null); 
        canvas.drawPath(paths.get(i), tempPaint); 
       } 
       //canvas.drawPath(paths.get(i), tempPaint); 
      } 
      if(_parent.toggleFill.isChecked()){ 
       mPaint.setStyle(Style.FILL_AND_STROKE); 
       eraserPaint.setStyle(Style.FILL_AND_STROKE); 

      }else{ 
       mPaint.setStyle(Style.STROKE); 
       eraserPaint.setStyle(Style.STROKE); 
      } 
      if(_parent.toggleErase.isChecked()){ 
       //mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 
       canvas.drawPath(mPath, eraserPaint); 
      }else{ 
       //mPaint.setXfermode(null); 
       canvas.drawPath(mPath, mPaint); 
      } 
      //canvas.drawPath(mPath, mPaint); 
     } 
    } 

    public void onClickUndo() { 

     if (paths.size() > 0) { 
      undonePaths.add(paths.remove(paths.size() - 1)); 
      undonePaints.add(paints.remove(paints.size() - 1)); 
      undoneFills.add(fills.remove(fills.size() - 1)); 
      undoneErasers.add(erasers.remove(erasers.size() - 1)); 
      clearCanvasCache(); 
      invalidate(); 
     } else { 

     } 
     _parent.checkButtonStates(); 
    } 

    public void onClickRedo() { 

     if (undonePaths.size() > 0) { 
      paths.add(undonePaths.remove(undonePaths.size() - 1)); 
      paints.add(undonePaints.remove(undonePaints.size() - 1)); 
      fills.add(undoneFills.remove(undoneFills.size() - 1)); 
      erasers.add(undoneErasers.remove(undoneErasers.size() - 1)); 
      clearCanvasCache(); 
      invalidate(); 
     } else { 

     } 
     _parent.checkButtonStates(); 
    } 

    public void onClickClear() { 

     paths.clear(); 
     paints.clear(); 
     fills.clear(); 
     erasers.clear(); 
     undoneFills.clear(); 
     undonePaths.clear(); 
     undonePaints.clear(); 
     undoneErasers.clear(); 
     clearCanvasCache(); 
     invalidate(); 
     _parent.checkButtonStates(); 
    } 

    public void saveDrawing() { 

     FileOutputStream outStream = null; 
     String fileName = "tempTag"; 
     try { 

      outStream = new FileOutputStream("/sdcard/" + fileName + ".png"); 

      mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream); 
      outStream.close(); 

     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
     } 

    } 

    private float mX, mY; 

    private static final float TOUCH_TOLERANCE = 4; 

    private void touch_start(float x, float y) { 

     undonePaths.clear(); 
     undonePaints.clear(); 
     undoneFills.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 
     if(_parent.toggleErase.isChecked()){ 
      mCanvas.drawPath(mPath, eraserPaint); 
      erasers.add(true); 
      paints.add(eraserPaint); 
     }else{ 
      mCanvas.drawPath(mPath, mPaint); 
      erasers.add(false); 
      paints.add(mPaint); 
     } 

     // kill this so we don't double draw 

     paths.add(mPath); 


     if(_parent.toggleFill.isChecked()){ 
      fills.add(true); 
     }else{ 
      fills.add(false); 
     } 
     if(_parent.toggleErase.isChecked()){ 
      erasers.add(true); 
     }else{ 
      erasers.add(false); 
     } 


     _parent.checkButtonStates(); 
     mPath = new Path(); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     if(mPaint==null &&!_parent._showingAlert){ 
      _parent.showNoPaintAlert(); 
     } 

     if (!_parent.isDrawerOpen()&&mPaint!=null) { 
      float x = event.getX(); 
      float y = event.getY(); 
      if (x > myWidth) { 
       x = myWidth; 

      } 
      if (y > myHeight) { 
       y = myHeight; 

      } 
      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; 
     } else { 
      return true; 
     } 
    } 

    public void clearCanvasCache() { 

     mBitmap = Bitmap.createBitmap((int) myWidth, (int) myHeight, Bitmap.Config.ARGB_8888); 
     mCanvas = new Canvas(mBitmap); 
    } 
} 

Vorrei aggiungere che io sono l'aggiunta di questa visualizzazione personalizzata a un layout parente che ha quel motivo a scacchi come il immagine di sfondo ..

PER FAVORE, PER FAVORE, aiuto .. ho bisogno di quell'immagine di anteprima per NON mostrare il nero dopo una gomma da cancellare w come usato .. ne ho bisogno per mostrare il motivo a scacchi dietro. So che la gomma funziona come quei segni di gomma nera salvati come trasparenti.

nuova nota

stavo giocando intorno e scoprii qualcos'altro thats curioso. Sperimentando, ho provato a passare dal disegno allocome passato al metodo onDraw e direttamente all'area di disegno che ho impostato nel contructor chiamato mCanvas e ho notato che non disegnava il più lontano possibile ... quindi ho aggiunto un log al onDraw in questo modo:

protected void onDraw(Canvas canvas) { 
     Log.v("DRAWING SURFACE", "canvas:"+canvas+" mCanvas:"+mCanvas); 

che sputa fuori

06-21 11:10:43.994: V/DRAWING SURFACE(4532): canvas:[email protected] mCanvas:[email protected] 
+0

a quanto pare, il colore nero che hai visto potrebbe essere il tratto, perchè è troppo alto, forse dovresti provare a rimuoverlo o puoi anche impostare il colore del tratto con questo. eraserPaint.setARGB (0, 0, 0, 0); –

+0

Non importa quello che faccio per la dimensione del tratto o il colore .. stessi risultati .. credo che ciò che sta accadendo è che funziona buit per qualche motivo la gomma sta tagliando tutto ed è nera .. CANT aggiustarlo ! – erik

+0

hmm, hai provato a cambiare lo stile della pittura? cambiarlo in FILL piuttosto che STROKE? –

risposta

7

ho avuto questo stesso problema con la mia app. Ho anche provato il codice di esempio "finger paint" e ho ancora avuto lo stesso problema. Non sono mai riuscito a far funzionare la gomma come percorso, ma sono riuscito a trovare una soluzione alternativa. Invece di disegnare un percorso quando ho cancellare, ho disegnare un cerchio (Potrebbe essere qualsiasi forma) quando l'utente mette il dito verso il basso o c'è un evento "mossa":

case MotionEvent.ACTION_DOWN: 
mPaint.setStrokeWidth(25); 
      mPaint.setXfermode(new PorterDuffXfermode(
        PorterDuff.Mode.CLEAR)); 
      mCanvas.drawCircle(x, y, 10, mPaint); 
      isErase = true; 
      invalidate(); 
     } 
     touch_start(x, y); 
     invalidate(); 
     break; 
case MotionEvent.ACTION_MOVE: 
     if(isErase) 
     { 
      mCanvas.drawCircle(x, y, 20, mPaint); 
     } 
     else{ 
      touch_move(x, y); 
     }invalidate(); 
     break; 

Ci vorrà del tempo per incorporare questo nel tuo codice, ma ti garantisco che ci vorrà meno tempo del tempo che hai già speso cercando di risolvere questo problema. Posso inviarti altro mio PaintView se pensi che sarebbe utile.

+0

darò uno scatto .. hai visto la nota che ho appena aggiunto sopra? Qualche idea sul perché il canvas passato a onDraw sia diverso da mCanvas? – erik

+0

Provato .. e lo stesso risultato – erik

+0

Il suo dipinto solo nero –

0

Questa è solo un'ipotesi: potrebbe essere correlata all'accelerazione hardware. Prova a disabilitare l'accelerazione hardware. Se ciò aiuta, puoi creare una bitmap della dimensione della vista, disegnare tutte le tue cose in quella bitmap e quindi disegnare la bitmap nella tela della vista.

1

Stesso problema riscontrato, provato tutte le altre soluzioni trovate, senza fortuna.

Ma ho trovato una soluzione. È possibile aggiungere una bitmap per memorizzare i tratti.

public void init(int width, int height) { 
    Log.i(TAG,"init with "+width+"x"+height); 
    foreground = Bitmap.createBitmap(width, height, Config.ARGB_8888); 
    cacheCanvas = new Canvas(); 
    cacheCanvas.setBitmap(foreground); 
} 

Ogni volta che c'è un tocco, registrare il tratto con la vernice corrente e la larghezza della corsa corrente. (la vernice potrebbe essere di qualsiasi colore, compresa la pittura della gomma)

E quindi sovrascrivere il metodo onDraw (Canvas). Poiché la bitmap supporta la gomma mentre la tela non lo fa, possiamo prima disegnare l'immagine risultante sulla bitmap e quindi disegnare la bitmap sulla tela.

@Override 
protected void onDraw(Canvas canvas) { 
    // Log.i(TAG,"onDraw called"); 
    synchronized (strokes) { 
     if (strokes.size() > 0) { 
      for (Stroke s : strokes) { 
       cacheCanvas.drawPath(s.path, s.color); 
      } 
      canvas.drawBitmap(foreground, 0, 0, null); 
      strokes.clear(); 
     } 
    } 
} 

FYI, se la bitmap in primo piano è molto grande, la prestazione sarà bassa. Per risolvere questo, dovremmo invalidare solo l'area che il tocco del dito più recente è stato modificato.

-2

È possibile utilizzare una variabile booleana durante la scelta della gomma (ad esempio isEraser = true) e in onDraw(), è possibile disegnare il percorso se non è gomma.

@Override 
protected void onDraw(Canvas canvas) { 
    if(!isEraser){ 
    canvas.drawPath(mPath, mPaint); 
    } 
} 
+1

Che non dipingerà solo le nuove forme, non "rimuoverà" quelle precedenti – Yorrd

0

Per la tela da cancellare e invalidare, è necessario impostare il setXfermode della tela su null. controlla l'ultima riga del codice.

+0

è meglio spiegare perché deve farlo –