画像のようなパスを描きたいです。2 つの黒い境界線があり、内側は透明ではなく白です。それを達成する方法は?特に関節の位置。
2 に答える
目的の結果を得るには、パスを部分的に描画する必要があります。
Paint
ストローク幅と色のみが異なる2 つの異なるオブジェクトを使用して、パーツを 2 回描画します。各パーツを描画した後、パスはリセットされます。コード コメントは残りを説明する必要があります。
public class SView extends View {
Path path;
Paint paint, paintWhite;
RectF rf, rf2, rf3;
public SView(Context context) {
super(context);
path = new Path();
// 'paint' has a wider stroke-width
// compared to 'paintWhite' and
// thus becomes the border paint
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
paint.setStrokeWidth(15);
paint.setStyle(Style.STROKE);
// 'paintWhite' colors the inner path
paintWhite = new Paint();
paintWhite.setColor(Color.WHITE);
paintWhite.setAntiAlias(true);
paintWhite.setStrokeWidth(12);
paintWhite.setStyle(Style.STROKE);
// For this example, we'll draw three
// arcs bound by the following RectF
// objects
rf = new RectF(200, 200, 500, 500);
rf2 = new RectF(200, 200, 400, 500);
rf3 = new RectF(100, 200, 400, 500);
}
@Override
protected void onDraw(Canvas canvas) {
// First arc bound by 'rf'
path.arcTo(rf, 0, 180);
// Draw 'path' using 'paint'
// and then, again using 'paintWhite'
canvas.drawPath(path, paint);
canvas.drawPath(path, paintWhite);
// Reset 'path' so as to clear
// history
path.reset();
// Repeat with the rest of arcs
path.arcTo(rf2, 180, 180);
canvas.drawPath(path, paint);
canvas.drawPath(path, paintWhite);
path.reset();
path.arcTo(rf3, 0, 180);
canvas.drawPath(path, paint);
canvas.drawPath(path, paintWhite);
}
}
出力:
注: オーバーラップする円弧は によってバインドされRectF rf3
、最後に描画されます。
white
と一緒に描いているのでborders
、十字路にはなりません。パーツは、flyover
描画された順序でオーバーラップします。
パフォーマンスを向上させるために (私が思うに)、パスをリセットする前に、パスの次の部分が前の部分と交差するかどうかを確認できます。次のパーツが交差する場合は、リセットして 2 つの Paint オブジェクトでパーツを描画します。そうでない場合は、パーツをパスに追加し、次の交差点まで待って描画します。もちろん、描画されたパーツの履歴を維持する必要があります (上記の例では、履歴には境界: 'RectF' オブジェクトが含まれます)。ただし、これがパスを繰り返しリセットしてからパーツを描画するよりも優れているかどうかは 100% わかりません。
2 つの異なる Paint オブジェクトを使用して、同じパスを描画することができます。最初の Paint オブジェクトには、境界線に必要な色と大きなストローク幅が含まれます。PorterDuff.Mode.CLEAR
2 番目のペイントは、設定されているとストローク幅が狭くなります。
linePaint = new Paint();
linePaint.setAntiAlias(true);
linePaint.setColor(Color.YELLOW);
linePaint.setStrokeWidth(6);
linePaint.setStyle(Paint.Style.STROKE);
clearPaint = new Paint();
clearPaint.setAntiAlias(true);
clearPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
clearPaint.setStyle(Paint.Style.STROKE);
clearPaint.setStrokeWidth(3);
次に onDraw() メソッドで、上記の 2 つのペイントを使用して同じパスを 2 回描画します。
canvas.drawPath(path, linePaint);
canvas.drawPath(path, clearPaint);
これはパフォーマンスの点ではあまり効率的ではないかもしれませんが、私が考えることができる最も簡単な方法です。
編集:これを自分で徹底的にテストしていないので、問題がある場合はお知らせください。
更新: これをテストした後、PorterDuff.Mode.CLEAR がキャンバスのバッキング ビットマップにあるピクセル情報全体をクリアすることがわかりました。したがって、通常は次のような結果になります。
これを修正する解決策は、パスを描画するオフスクリーン キャンバスを作成することです。
Canvas canvas2 = new Canvas();
Bitmap backingBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
canvas2.setBitmap(backingBitmap);
canvas2.drawPaint(clearPaint);
canvas2.drawPath(path, linePaint);
canvas2.drawPath(path, clearPaint);
canvas.drawBitmap(backingBitmap, 0, 0, null);
上記の方法を使用すると、次の結果が得られます。
欠点は、フレームごとにビットマップを作成すると、パフォーマンスが低下する可能性があることです。ビットマップのサイズもパフォーマンスに悪影響を及ぼします。そのため、必要な場合にのみオフスクリーン キャンバスを作成し、パス情報をリセットする必要がない限り、以前に作成した backingBitmap に描画を続けることができます。