4つの角すべてが丸い長方形の関数を見つけましたが、上の2つの角だけを丸くしたいです。私に何ができる?
canvas.drawRoundRect(new RectF(0, 100, 100, 300), 6, 6, Paint);
Canvas
のdrawLine()
およびdrawArc()
関数を使用して、そのピースを1つずつ描画できます。
パスを使用します。 21未満のAPIで動作するという利点があります(したがって、Arcも制限されているため、クワッドです)。誰もがまだロリポップを持っているわけではないので、これは問題です。ただし、RectFを指定して値を設定し、アークをAPI 1に戻すことはできますが、静的オブジェクトを使用することはできません(新しいオブジェクトを宣言してオブジェクトを構築することはできません)。
角丸長方形の描画:
path.moveTo(right, top + ry);
path.rQuadTo(0, -ry, -rx, -ry);
path.rLineTo(-(width - (2 * rx)), 0);
path.rQuadTo(-rx, 0, -rx, ry);
path.rLineTo(0, (height - (2 * ry)));
path.rQuadTo(0, ry, rx, ry);
path.rLineTo((width - (2 * rx)), 0);
path.rQuadTo(rx, 0, rx, -ry);
path.rLineTo(0, -(height - (2 * ry)));
path.close();
完全な機能として:
static public Path RoundedRect(float left, float top, float right, float bottom, float rx, float ry, boolean conformToOriginalPost) {
Path path = new Path();
if (rx < 0) rx = 0;
if (ry < 0) ry = 0;
float width = right - left;
float height = bottom - top;
if (rx > width/2) rx = width/2;
if (ry > height/2) ry = height/2;
float widthMinusCorners = (width - (2 * rx));
float heightMinusCorners = (height - (2 * ry));
path.moveTo(right, top + ry);
path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
path.rLineTo(-widthMinusCorners, 0);
path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
path.rLineTo(0, heightMinusCorners);
if (conformToOriginalPost) {
path.rLineTo(0, ry);
path.rLineTo(width, 0);
path.rLineTo(0, -ry);
}
else {
path.rQuadTo(0, ry, rx, ry);//bottom-left corner
path.rLineTo(widthMinusCorners, 0);
path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
}
path.rLineTo(0, -heightMinusCorners);
path.close();//Given close, last lineto can be removed.
return path;
}
四角ではなく、それらの隅の部分までずっと並べたいと思うでしょう。これは、conformToOriginalPostにtrueを設定することです。そこにあるコントロールポイントに向かってください。
ロリポップ以前のものを気にせずにすべてを行いたい場合は、rxとryが十分に高い場合は円を描く必要があることを緊急に主張します。
@TargetApi(Build.VERSION_CODES.Lollipop)
static public Path RoundedRect(float left, float top, float right, float bottom, float rx, float ry, boolean conformToOriginalPost) {
Path path = new Path();
if (rx < 0) rx = 0;
if (ry < 0) ry = 0;
float width = right - left;
float height = bottom - top;
if (rx > width/2) rx = width/2;
if (ry > height/2) ry = height/2;
float widthMinusCorners = (width - (2 * rx));
float heightMinusCorners = (height - (2 * ry));
path.moveTo(right, top + ry);
path.arcTo(right - 2*rx, top, right, top + 2*ry, 0, -90, false); //top-right-corner
path.rLineTo(-widthMinusCorners, 0);
path.arcTo(left, top, left + 2*rx, top + 2*ry, 270, -90, false);//top-left corner.
path.rLineTo(0, heightMinusCorners);
if (conformToOriginalPost) {
path.rLineTo(0, ry);
path.rLineTo(width, 0);
path.rLineTo(0, -ry);
}
else {
path.arcTo(left, bottom - 2 * ry, left + 2 * rx, bottom, 180, -90, false); //bottom-left corner
path.rLineTo(widthMinusCorners, 0);
path.arcTo(right - 2 * rx, bottom - 2 * ry, right, bottom, 90, -90, false); //bottom-right corner
}
path.rLineTo(0, -heightMinusCorners);
path.close();//Given close, last lineto can be removed.
return path;
}
したがって、conformToOriginalPostは実際には、下の2ビットが丸められずに、丸みのある長方形を描画します。
2つの四角形を描画します。
canvas.drawRect(new RectF(0, 110, 100, 290), Paint);
canvas.drawRoundRect(new RectF(0, 100, 100, 200), 6, 6, Paint);
またはそのようなもの、それらを単にオーバーラップして、上部の角が丸くなるようにします。できれば、このためのメソッドを書く必要があります
Kotlinで記述された単純なヘルパー関数。
private fun Canvas.drawTopRoundRect(rect: RectF, Paint: Paint, radius: Float) {
// Step 1. Draw rect with rounded corners.
drawRoundRect(rect, radius, radius, Paint)
// Step 2. Draw simple rect with reduced height,
// so it wont cover top rounded corners.
drawRect(
rect.left,
rect.top + radius,
rect.right,
rect.bottom,
Paint
)
}
使用法:
canvas.drawTopRoundRect(rect, Paint, radius)
public static Path composeRoundedRectPath(RectF rect, float topLeftDiameter, float topRightDiameter,float bottomRightDiameter, float bottomLeftDiameter){
Path path = new Path();
topLeftDiameter = topLeftDiameter < 0 ? 0 : topLeftDiameter;
topRightDiameter = topRightDiameter < 0 ? 0 : topRightDiameter;
bottomLeftDiameter = bottomLeftDiameter < 0 ? 0 : bottomLeftDiameter;
bottomRightDiameter = bottomRightDiameter < 0 ? 0 : bottomRightDiameter;
path.moveTo(rect.left + topLeftDiameter/2 ,rect.top);
path.lineTo(rect.right - topRightDiameter/2,rect.top);
path.quadTo(rect.right, rect.top, rect.right, rect.top + topRightDiameter/2);
path.lineTo(rect.right ,rect.bottom - bottomRightDiameter/2);
path.quadTo(rect.right ,rect.bottom, rect.right - bottomRightDiameter/2, rect.bottom);
path.lineTo(rect.left + bottomLeftDiameter/2,rect.bottom);
path.quadTo(rect.left,rect.bottom,rect.left, rect.bottom - bottomLeftDiameter/2);
path.lineTo(rect.left,rect.top + topLeftDiameter/2);
path.quadTo(rect.left,rect.top, rect.left + topLeftDiameter/2, rect.top);
path.close();
return path;
}
API 21以降では、Pathクラスに新しいメソッドaddRoundRect()
が追加され、このように使用できます。
corners = new float[]{
80, 80, // Top left radius in px
80, 80, // Top right radius in px
0, 0, // Bottom right radius in px
0, 0 // Bottom left radius in px
};
final Path path = new Path();
path.addRoundRect(rect, corners, Path.Direction.CW);
canvas.drawPath(path, mPaint);
コトリンで
val corners = floatArrayOf(
80f, 80f, // Top left radius in px
80f, 80f, // Top right radius in px
0f, 0f, // Bottom right radius in px
0f, 0f // Bottom left radius in px
)
val path = Path()
path.addRoundRect(rect, corners, Path.Direction.CW)
canvas.drawPath(path, mPaint)
以下の手順に従ってこれを達成しました。
これらは、丸みを帯びた長方形がきれいに見えるための前提条件です
次は、角丸四角形を描画する手順です。
最初に、半径=長方形の高さ/ 2で、左右に2つの円を描きます
次に、これらの円の間に長方形を描き、目的の丸い長方形を取得します。
私は以下のコードを投稿しています
private void drawRoundedRect(Canvas canvas, float left, float top, float right, float bottom) {
float radius = getHeight() / 2;
canvas.drawCircle(radius, radius, radius, mainPaint);
canvas.drawCircle(right - radius, radius, radius, mainPaint);
canvas.drawRect(left + radius, top, right - radius, bottom, mainPaint);
}
ソリッドサイドを描画する簡単で効率的な方法の1つは、クリッピングを使用することです。長方形のクリッピングは基本的に無料で、カスタムパスよりも記述するコードがはるかに少なくなります。
左上と右を50ピクセルで丸めた300x300の四角形が必要な場合は、次の操作を実行できます。
canvas.save();
canvas.clipRect(0, 0, 300, 300);
canvas.drawRoundRect(new RectF(0, 0, 300, 350), 50, 50, Paint);
canvas.restore();
このアプローチは、隣接する2つまたは3つのコーナーでのラウンドでのみ機能するため、Pathベースのアプローチよりも設定が少し少なくなりますが、drawRoundRect()は完全にハードウェアアクセラレーションされる(つまり、三角形にテッセレーションされる)ため、ラウンド四角形を使用する方が効率的です一方、drawPath()は常にソフトウェアレンダリングにフォールバックします(ソフトウェアでパスビットマップを描画し、GPUにキャッシュするためにアップロードします)。
小さい頻度の描画では大きなパフォーマンスの問題ではありませんが、パスをアニメーション化する場合、ソフトウェア描画のコストによりフレーム時間が長くなり、フレームをドロップする可能性が高くなります。パスマスクもメモリを消費します。
パスベースのアプローチを使用する場合は、GradientDrawableを使用してコード行を簡略化することをお勧めします(カスタムシェーダーを設定する必要がない場合、たとえばビットマップを描画する場合)。
mGradient.setBounds(0, 0, 300, 300);
mGradient.setCornerRadii(new int[] {50,50, 50,50, 0,0, 0,0});
GradientDrawable#setCornerRadii() を使用すると、任意の角を任意の丸みに設定し、状態間を合理的にアニメーション化できます。
左の角が丸い長方形を描く
private void drawRoundRect(float left, float top, float right, float bottom, Paint paint, Canvas canvas) {
Path path = new Path();
path.moveTo(left, top);
path.lineTo(right, top);
path.lineTo(right, bottom);
path.lineTo(left + radius, bottom);
path.quadTo(left, bottom, left, bottom - radius);
path.lineTo(left, top + radius);
path.quadTo(left, top, left + radius, top);
canvas.drawPath(path, onlinePaint);
}
PaintDrawable を使用することをお勧めします。
val topLeftRadius = 10
val topRightRadius = 10
val bottomLeftRadius = 0
val bottomRightRadius = 0
val rect = Rect(0, 0, 100, 100)
val paintDrawable = PaintDrawable(Color.RED)
val outter = floatArrayOf(topLeftRadius, topLeftRadius, topRightRadius, topRightRadius,
bottomLeftRadius, bottomLeftRadius, bottomRightRadius, bottomRightRadius)
paintDrawable.setCornerRadii(outter)
paintDrawable.bounds = rect
paintDrawable.draw(canvas)
これは古い質問ですが、多くのカスタムコードやハッキーな描画なしでネイティブSDKを使用するため、ソリューションを追加したかったのです。このソリューションは、API 1でサポートされます。
これを適切に行う方法は、パスを作成することです(他の回答で述べたように)が、以前の回答では、各コーナーの半径を取るaddRoundedRect
関数呼び出しを見落としているようです。
変数
private val path = Path()
private val Paint = Paint()
塗料の設定
Paint.color = Color.RED
Paint.style = Paint.Style.FILL
サイズ変更でパスを更新
これは、onDrawではない場所、たとえばビューの場合はonMeasure
、ドロアブルの場合はonBoundChange
のように呼び出します。 (この例のように)変わらない場合は、ペイントを設定した場所にこのコードを配置できます。
val radii = floatArrayOf(
25f, 25f, //Top left corner
25f, 25f, //Top right corner
0f, 0f, //Bottom right corner
0f, 0f, //Bottom left corner
)
path.reset() //Clears the previously set path
path.addRoundedRect(0f, 0f, 100f, 100f, radii, Path.Direction.CW)
このコードは、角が半径25で丸みを帯びた100x100の角丸長方形を作成します。
パスの描画
ビューの場合はonDraw
で、またはドロアブルの場合はdraw
でこれを呼び出します。
canvas.drawPath(path, Paint)