4つの角がすべて丸い長方形の関数を見つけましたが、上の2つの角だけを丸くしたいと思います。私に何ができる?
canvas.drawRoundRect(new RectF(0, 100, 100, 300), 6, 6, paint);
4つの角がすべて丸い長方形の関数を見つけましたが、上の2つの角だけを丸くしたいと思います。私に何ができる?
canvas.drawRoundRect(new RectF(0, 100, 100, 300), 6, 6, paint);
パスを使用します。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);
またはそのようなもの、あなたはちょうどそれらを重ねて、上部の角が丸くなるようにします。できれば、このためのメソッドを作成する必要があります
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);
Kotlinで
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)
この答えを変更し て、どのコーナーを丸くしたいのか、どのコーナーをシャープにしたいのかを設定できるようにしました。プレロリポップでも動作します
使用例:右上と右下の角だけが丸みを帯びています
Path path = RoundedRect(0, 0, fwidth , fheight , 5,5,
false, true, true, false);
canvas.drawPath(path,myPaint);
public static Path RoundedRect(
float left, float top, float right, float bottom, float rx, float ry,
boolean tl, boolean tr, boolean br, boolean bl
){
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);
if (tr)
path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
else{
path.rLineTo(0, -ry);
path.rLineTo(-rx,0);
}
path.rLineTo(-widthMinusCorners, 0);
if (tl)
path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
else{
path.rLineTo(-rx, 0);
path.rLineTo(0,ry);
}
path.rLineTo(0, heightMinusCorners);
if (bl)
path.rQuadTo(0, ry, rx, ry);//bottom-left corner
else{
path.rLineTo(0, ry);
path.rLineTo(rx,0);
}
path.rLineTo(widthMinusCorners, 0);
if (br)
path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
else{
path.rLineTo(rx,0);
path.rLineTo(0, -ry);
}
path.rLineTo(0, -heightMinusCorners);
path.close();//Given close, last lineto can be removed.
return path;
}
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)
パスを使用すると、これを簡単に実現できます。
val radiusArr = floatArrayOf(
15f, 15f,
15f, 15f,
0f, 0f,
0f, 0f
)
val myPath = Path()
myPath.addRoundRect(
RectF(0f, 0f, 400f, 400f),
radiusArr,
Path.Direction.CW
)
canvas.drawPath(myPath, paint)
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;
}
私は以下の手順に従ってこれを達成しました。
これらは、丸みを帯びた長方形がきれいに見えるための前提条件です。
次は、角の丸い長方形を描く手順です。
まず、半径=長方形の高さ/ 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);
}
これは古い質問ですが、多くのカスタムコードやハッキーな描画を行わずにネイティブSDKを使用しているため、ソリューションを追加したいと思いました。このソリューションは、API1に戻ってサポートされます。
これを適切に行う方法は、パスを作成することです(他の回答で述べたように)が、前の回答はaddRoundedRect
、各コーナーの半径を取る関数呼び出しを見落としているようです。
変数
private val path = Path()
private val paint = Paint()
セットアップペイント
paint.color = Color.RED
paint.style = Paint.Style.FILL
サイズ変更でパスを更新
onMeasure
ビューやドローアブルなど、onDrawではない場所でこれを呼び出し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)
ソリッドサイドを描画する簡単で効率的な方法の1つは、クリッピングを使用することです。rectクリッピングは基本的に無料であり、カスタムパスよりもはるかに少ないコードで記述できます。
左上と右上を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つのコーナーでの丸めに対してのみ機能するため、パスベースのアプローチよりも構成が少し難しくなりますが、drawRoundRect()は完全にハードウェアアクセラレーションされている(つまり、三角形にテッセレートされている)ため、ラウンドレクを使用する方が効率的です。一方、drawPath()は常にソフトウェアレンダリングにフォールバックします(ソフトウェア-パスビットマップを描画し、それをアップロードしてGPUにキャッシュします)。
頻度の低い小さな描画では大きなパフォーマンスの問題ではありませんが、パスをアニメーション化する場合、ソフトウェア描画のコストによってフレーム時間が長くなり、フレームをドロップする可能性が高くなります。パスマスクもメモリを消費します。
パスベースのアプローチを使用する場合は、GradientDrawableを使用してコード行を簡略化することをお勧めします(たとえば、ビットマップを描画するためにカスタムシェーダーを設定する必要がない場合)。
mGradient.setBounds(0, 0, 300, 300);
mGradient.setCornerRadii(new int[] {50,50, 50,50, 0,0, 0,0});
GradientDrawable#setCornerRadii()を使用すると、任意のコーナーを任意の丸みに設定し、状態間で合理的にアニメーション化できます。
drawLine()
を使用して、drawArc()
から関数を使用して、その部分を1つずつ描画できますCanvas
。
半径が高さの半分の場合に丸みを帯びた辺を描画するPath#arcTo()バージョン。
fun getPathOfRoundedRectF(
rect: RectF,
topLeftRadius: Float = 0f,
topRightRadius: Float = 0f,
bottomRightRadius: Float = 0f,
bottomLeftRadius: Float = 0f
): Path {
val tlRadius = topLeftRadius.coerceAtLeast(0f)
val trRadius = topRightRadius.coerceAtLeast(0f)
val brRadius = bottomRightRadius.coerceAtLeast(0f)
val blRadius = bottomLeftRadius.coerceAtLeast(0f)
with(Path()) {
moveTo(rect.left + tlRadius, rect.top)
//setup top border
lineTo(rect.right - trRadius, rect.top)
//setup top-right corner
arcTo(
RectF(
rect.right - trRadius * 2f,
rect.top,
rect.right,
rect.top + trRadius * 2f
), -90f, 90f
)
//setup right border
lineTo(rect.right, rect.bottom - trRadius)
//setup bottom-right corner
arcTo(
RectF(
rect.right - brRadius * 2f,
rect.bottom - brRadius * 2f,
rect.right,
rect.bottom
), 0f, 90f
)
//setup bottom border
lineTo(rect.left + blRadius, rect.bottom)
//setup bottom-left corner
arcTo(
RectF(
rect.left,
rect.bottom - blRadius * 2f,
rect.left + blRadius * 2f,
rect.bottom
), 90f, 90f
)
//setup left border
lineTo(rect.left, rect.top + tlRadius)
//setup top-left corner
arcTo(
RectF(
rect.left,
rect.top,
rect.left + tlRadius * 2f,
rect.top + tlRadius * 2f
),
180f,
90f
)
close()
return this
}
}
左の丸い角で丸い長方形を描く
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)
上記の質問に対する私の答えは次のとおりです。ここでは、低レベルのAPIでも使用できる関数とPath
一緒に使用するKotlin拡張関数を作成しました。quadTo
fun Canvas.drawRoundRectPath(
rectF: RectF,
radius: Float,
roundTopLeft: Boolean,
roundTopRight: Boolean,
roundBottomLeft: Boolean,
roundBottomRight: Boolean,
paint: Paint) {
val path = Path()
//Move path cursor to start point
if (roundBottomLeft) {
path.moveTo(rectF.left, rectF.bottom - radius)
} else {
path.moveTo(rectF.left, rectF.bottom)
}
// drawing line and rounding top left curve
if (roundTopLeft) {
path.lineTo(rectF.left, rectF.top + radius)
path.quadTo(rectF.left, rectF.top, rectF.left + radius, rectF.top)
} else {
path.lineTo(rectF.left, rectF.top)
}
// drawing line an rounding top right curve
if (roundTopRight) {
path.lineTo(rectF.right - radius, rectF.top)
path.quadTo(rectF.right, rectF.top, rectF.right, rectF.top + radius)
} else {
path.lineTo(rectF.right, rectF.top)
}
// drawing line an rounding bottom right curve
if (roundBottomRight) {
path.lineTo(rectF.right, rectF.bottom - radius)
path.quadTo(rectF.right, rectF.bottom, rectF.right - radius, rectF.bottom)
} else {
path.lineTo(rectF.right, rectF.bottom)
}
// drawing line an rounding bottom left curve
if (roundBottomLeft) {
path.lineTo(rectF.left + radius, rectF.bottom)
path.quadTo(rectF.left, rectF.bottom, rectF.left, rectF.bottom - radius)
} else {
path.lineTo(rectF.left, rectF.bottom)
}
path.close()
drawPath(path, paint)
}
キャンバスオブジェクトを使用して関数を呼び出し、RectF
曲線を適用するディメンションを使用してを渡すことができます。
また、丸めたいコーナーのブール値を渡すことができます。この回答は、個々のコーナーの半径を受け入れるようにさらにカスタマイズできます。
たぶん、次のコードがあなたを助けることができます
Paint p = new Paint();
p.setColor(color);
float[] corners = new float[]{
15, 15, // Top, left in px
15, 15, // Top, right in px
15, 15, // Bottom, right in px
15, 15 // Bottom,left in px
};
final Path path = new Path();
path.addRoundRect(rect, corners, Path.Direction.CW);
// Draw
canvas.drawPath(path, p);