はじめに
表題の通りです。
できる限り onTapGesture { ... } より Button を使いましょう。
// 🔺: `onTapGesture` を `Button` として使っている
FooView(foo: foo)
.onTapGesture {
print("FooView tapped.")
}
.accessibilityAddTraits(.isButton)
// ✅: `Button` を使っている
Button {
print("FooView tapped.")
} label: {
FooView(foo: foo)
}
Button の label には View を渡せるので、リファクタリングも簡単です。
環境
- OS:macOS Ventura 13.3.1
- Xcode:14.3 (14E222b)
- Swift:5.8
理由
できる限り onTapGesture { ... } より Button を使う理由を紹介します。
公式ドキュメントに記載されている
onTapGestureの公式ドキュメント に以下の記載があります。
Note
If you create a control that’s functionally equivalent to a Button, use ButtonStyle to create a customized button instead.
(ボタンと同等の機能を持つコントロールを作成する場合は、 ButtonStyleを使用して、代わりにカスタマイズされたボタンを作成します。)
Button と同等のコントロールなら Button を使いましょう、と明記されています。
最初の例では label に FooView をそのまま渡しましたが、 部品化するなら ButtonStyle を実装するのがいいと思います。
PrimitiveButtonStyle を使うのがいいとのことです。
タップ時にハイライトが付く
個人的には Button を使う一番の理由です。
onTapGesture だとタップ時にハイライトが付かないので、タップしたかどうかがわかりづらいです。
Button はデフォルトでハイライトが付きます。
ただ ButtonStyle を自作する場合、ハイライト処理を自前で実装する必要があります。
struct FloatingActionButtonStyle: ButtonStyle {
let backgroundColor: Color
let foregroundColor: Color
func makeBody(configuration: Configuration) -> some View {
configuration.label
.frame(width: 56, height: 56)
.foregroundColor(foregroundColor)
.background(backgroundColor)
.cornerRadius(16)
+ .opacity(configuration.isPressed ? 0.5 : 1)
}
}
といっても1行のみの実装で済みます。
Swift Playgroundsでスニペットを使って ButtonStyle を作ると、最初から書かれている処理です。
おわりに
タップ時の処理に onTapGesture を使っていたら、ぜひ Button に置き換えてハイライトが付くライフを送りましょう ![]()