[Jetpack Compose] Modiferのborderについて調べてみた
はじめに
Compose の border の描画位置について調べてみました。
border は compose のサイズに影響するのかななどが分かります。
結論
Compose の border は描画の内部に描画されます。
つまり 5dp の border で 50dp の Box があった場合、大きさは 50dp で変わらず、中身は 40dp(50-5-5)になります。
コードを読む
border 関数の中身を見ると、適用する要素の shape 次第で drawGenericBorder
、drawRoundRectBorder
、drawRectBorder
の分岐があります。これはカスタムボーダー、丸縁の長方形、普通の長方形という感じでしょうか。
一番簡単そうなdrawRectBorder
を見てみます。
関数は以下のように呼び出しを行っています。
private fun CacheDrawScope.drawRectBorder(
brush: Brush,
topLeft: Offset,
borderSize: Size,
fillArea: Boolean,
strokeWidthPx: Float
): DrawResult {...}
描画される位置が知りたいので、位置に関係しそうなパラメータである、topLeft
とbroderSize
とstrokeWidthPx
などを確認します。
まずはstrokeWidth
ですが、以下の値を渡しています。
以下のことが分かりました。
- border の width が 0 でも 1px の幅になる!
- dp→px の変換で少数派切り捨て!
- width が大きすぎる場合、短辺/2 の大きさになる(溢れたりはしない)
val strokeWidthPx = min(
if (width == Dp.Hairline) 1f else ceil(width.toPx()),
ceil(size.minDimension / 2)
)
次はborderSize
です。以下の値を渡しています。(この部分記事の最後の方の図で説明しています。)
val borderSize = Size(
size.width - strokeWidthPx,
size.height - strokeWidthPx
)
まずはtopLeft
ですが、以下の値を渡しています。(この部分記事の最後の方の図で説明しています。)
val halfStroke = strokeWidthPx / 2
val topLeft = Offset(halfStroke, halfStroke)
またfillArea
という boolean も渡しているようで、後で使いそう(使う)ので念のため確認しておきます。
border 幅の二倍が短変のサイズより大きければ、おそらく fillMax で描画せよっていう流れが予測できますね。
val fillArea = (strokeWidthPx * 2) > size.minDimension
引数に何を渡しているかだいたい分かったので、実際に描画するところを見てみましょう。
まぁ当然ですが、drawConotent
で設定済みの content を描画、その後に border を描画していることがわかりますね。
fillArea
によって size(全体か border 幅を考慮するか)や style(Fill か Stroke か)が異なることが分かります。
いずれにせよ border をどんな値に設定しようとも、コンテンツ幅より大きくなることはなく、コンテンツの内側に描画されることが分かりました!
val rectTopLeft = if (fillArea) Offset.Zero else topLeft
val size = if (fillArea) size else borderSize
val style = if (fillArea) Fill else Stroke(strokeWidthPx)
return onDrawWithContent {
drawContent()
drawRect(
brush = brush,
topLeft = rectTopLeft,
size = size,
style = style
)
}
さらに自分がはじめて知ったこととして上記のように Stroke を指定した場合や、他にもdrawLine
を指定したとき、その幅は offset の点を中心に左右(または上下)に広がるということです。何が言いたいかというと言葉だと難しいので図で説明します。(ダサい図許して)
まとめ
はい、Jetpack Compose の border に関して、描画位置を調べてみました。ものすごく簡単な内容ですが、調べる前はどうなっているんだろう?だったので、読んで記事にして良かったです。
私は当初 border は要素の外側に描画されたら、要素自体のサイズも変わってしまうのではないか?と思い、つまり、Compose の 3 フェーズの一つである Layout フェーズにも影響してしまうのか?どうなっているんだ??と疑問を持ち、ささっと確認してみました。
もっと Modifier のコード読んで行きたいですね~
Discussion