2017-06-08 9 views
0

私はdrawPathをsurfaceViewにする必要があるカメラアプリケーションに取り組んでいます。
surfaceViewは、カメラのプレビューに使用されます。画像をキャプチャした後、私はそれにパスを描く必要があります。すべてがうまくいっています。しかし、最初のパスを描画するときは大丈夫ですが、別のパスを描くときは前のパスを削除します。androidのSurfaceViewのDrawPath

ここに私が使用しているコードがあります。

// Class is extended from surfaceView and implements SurfaceHolder.Callback 
@Override 
protected void onDraw(Canvas canvas) { 
    Log.i(TAG, "onDraw"); 
    canvas.drawPath(drawPath, drawPaint); 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    float touchX = event.getX(); 
    float touchY = event.getY(); 
    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      drawCanvas = surfaceHolder.lockCanvas(); 
      drawPath.moveTo(touchX, touchY); 
      break; 
     case MotionEvent.ACTION_MOVE: 
      drawPath.lineTo(touchX, touchY); 
      break; 
     case MotionEvent.ACTION_UP: 
      drawCanvas.drawPath(drawPath, drawPaint); 
      drawPath.reset(); 
      surfaceHolder.unlockCanvasAndPost(drawCanvas); 
      break; 
     default: 
      return false; 
    } 
    invalidate(); 
    return true; 
} 
// other code 

問題:あなたはそれはあなたが私が私が間違ってやっている聞かせてくださいでき最初の1

を削除し、別のパスを描画しようとする場合は、パスを初めて描くことができます。

+0

「私が間違っていることを教えてもらえますか?」何が間違っていますか? – Zoe

+0

@ LunarWatcher私はすでに「最初のパスを描くために別のパスを描画しようとするとパスを初めて描画できます」と述べています。 –

答えて

1

ルナワッチャーは非常に正しいです。

私はちょうど彼の答えでいくつかの変更を加えました。 ArrayListと同様に、それぞれ現在のpathが必要です。foreachループをonDrawの方法で使用すると、LunarWatcherによると、ユーザーが描画を終了するまで描画パスを確認することができないためです。

ここで私はテストして正常に動作するコードです。

private ArrayList<Path> drawPath; 
private Path path; 

public constructor(){ 
    drawPath = new ArrayList<Path>(); 
    path = null; 
} 

@Override 
protected void onDraw(Canvas canvas) { 
    canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); 
    if(path != null) { 
     canvas.drawPath(path, drawPaint); 
    } 
    for(Path p : drawPath) { 
      canvas.drawPath(p, drawPaint); 
    } 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    float touchX = event.getX(); 
    float touchY = event.getY(); 
    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      drawCanvas = surfaceHolder.lockCanvas(); 
      path = new Path(); 
      path.moveTo(touchX, touchY); 
      break; 
     case MotionEvent.ACTION_MOVE: 
      path.lineTo(touchX, touchY); 
      break; 
     case MotionEvent.ACTION_UP: 
      drawCanvas.drawPath(path, drawPaint); 
      drawPath.add(new Path(path)); 
      path.reset(); 
      surfaceHolder.unlockCanvasAndPost(drawCanvas); 
      break; 
     default: 
      return false; 
    } 
    invalidate(); 
    return true; 
} 

これはうまくいきます。

0

キャンバスがinvalidateの場合は、基本的にキャンバスを消去してコンテンツを再描画します。以前にキャンバスにあったものが削除されたことを意味します。移動オブジェクトを作成してキャンバスを無効にすると、オブジェクトが移動し、描画された古い場所が表示されなくなります。最初のものが消える理由は、2番目のものを描画した後に再描画しないためです。

はこのことを考えてみましょう:偽となる

if(something) 
    canvas.drawRect(0,0,10,10); 

something場合は、そのオブジェクトを描画しないとそれが消えます。レンダリングされないので、以前にあったとしても表示されません。

パスと同じです。あなたは:

drawCanvas.drawPath(drawPath, drawPaint); 

単一のパスです。つまり、そのパスを新しいパスに置き換えると、古いパスが消えます。

マイナーな改善:

あなたは二回、それを再描画するので、手動でキャンバス使用invalidateにそれを描画する必要はありません。本当に非効率的です。

ソリューション:

drawPathsのArrayListのを作成し、ポインタが削除されたとき、あなたは現在のパスを追加します。

次にあなたがonDrawでレンダリングする場合:

for(Path p : paths){ 
    //render here 
} 

あなたの代わりに、最新のすべてのパスをレンダリングするこの方法です。最新のものだけをレンダリングすると、古いパスが消え、発生した問題が発生します。

+0

大きな説明、 'surfaceView'から拡張する前に、' View'これでうまくいきます。あなたが 'View'からそれを拡張すると、これはうまくいくのですか? –

+0

私は本当にわかりません – Zoe

関連する問題