しみじみ勉強してきたのに、
なぜか簡単に作れないこういうボタン。
ので、少しやってみました。
VIDEO
まず思いついた記述
便利な BorderdProminentButtonStyle()
に .overlay()
で 角丸枠線をのせます。
Button {
} label: {
VStack {
Label ( "BorderedProminent" , systemImage: "face.smiling" )
Text ( ".overlay()" )
. font ( . caption)
}
. padding ( )
}
. buttonStyle ( . borderedProminent)
. tint ( . orange)
#if os( macOS)
. clipShape ( . rect ( cornerRadius: 16 ) )
#endif
. overlay ( RoundedRectangle ( cornerRadius: 16 ) . stroke ( . gray) )
macOS では角がずれる。
ので、clipShape()
しました。
気持ち悪いですね。
よくある記述
この書き方が多いらしいです。
ラベル の View に modifier のチェイン。
Button {
} label: {
VStack {
Label ( "Plain" , systemImage: "face.smiling" )
Text ( ".background(.orange, in: .rect(cornerRadius: 16))" )
. font ( . caption)
Text ( ".overlay()" )
. font ( . caption)
}
. foregroundStyle ( . white)
. padding ( )
. background ( . orange, in : . rect ( cornerRadius: 16 ) )
. overlay ( RoundedRectangle ( cornerRadius: 16 ) . stroke ( . gray) )
}
. buttonStyle ( . plain)
ButtonStyle は .plain
一択でしたが、
見た目も、ボタンを押したときの挙動も、
問題ないように見えます。
ただ、コードが長ったらしくなるので、
同様なボタンの数が増えると見通しが悪くなりそうです。
カスタム ButtonStyle
ビルトインにあっても良さそうなのに。
押したときエフェクトは、BorderdProminentButtonStyle()
になるべく似せて ButtonStyle を作ります。
struct StrokeRoundedRectangleButtonStyle : ButtonStyle {
var cornerRadius: CGFloat
func makeBody ( configuration: Configuration ) -> some View {
configuration. label
. foregroundStyle (
. white. opacity ( configuration. isPressed ? 0.75 : 1 )
)
. padding ( )
. background (
. orange. opacity ( configuration. isPressed ? 0.75 : 1 ) ,
in : . rect ( cornerRadius: cornerRadius)
)
. overlay (
RoundedRectangle ( cornerRadius: cornerRadius)
. stroke ( . gray. opacity ( configuration. isPressed ? 0.75 : 1 ) )
)
}
}
extension ButtonStyle where Self == StrokeRoundedRectangleButtonStyle {
static var strokeRounded: Self { Self ( cornerRadius: 16 ) }
}
ButtonStyle を作ってしまえば、あとは簡単にボタンに適用できます。
Button {
} label: {
VStack {
Label ( "Custom Button Style" , systemImage: "face.smiling" )
Text ( "extension " )
. font ( . caption)
}
}
. buttonStyle ( . strokeRounded)
しかし、コード量は多い。
まとめ
レイアウトの重なりの考え方として、この場合は、
角を丸くするのは .background()
で、
枠線はそれに合わせて .overlay()
する、
のが良さげに思えました。
あと、
iOS と macOS のコード共用は、シビアなレイアウトになると厳しいのですね!
Customizing the Appearance and Interaction Behavior of Buttons | Fatbobman's Blog