🙄
【SwiftUI】TextFieldのタップエリアが狭すぎる
SwiftUI Tipsです。
問題
このようなデザインのSwiftUIの入力フィールドを実装しました。

TextFieldの範囲に対して、ちょっとマージンがあって、枠線があるデザインです。
コードは↓こんな実装です。
struct MailInputView: View {
@State var email: String = ""
@FocusState private var focusedField: Field?
enum Field: Hashable {
case email
}
var body: some View {
TextField("メールアドレス", text: $email)
.font(.body)
.keyboardType(.emailAddress)
.padding(.horizontal, 8)
.frame(height: 48)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(.gray, lineWidth: 1)
)
.padding()
.focused($focusedField, equals: .email)
}
}
これで最低限の機能は実現できるんですが、実機で触ってみると
「なんかタップ範囲やたら狭いな」という感覚がありました。
なぜそう感じたのかというと、タップ範囲が↓このエリアになるためです。

視覚的にはグレー線の中が全てタップ可能と感じますが、
実際はTextFieldがタップ範囲なので、実際は赤線の中になります。
対策
SwiftUIのタップ範囲について調べると、だいたい.contentShapeつけて、.onTapGestureをつけろというアドバイスが出てきます。
今回のケースでもこのアプローチしかなさそうです。
本当はTextFieldにタップ範囲広くできる何かがあると良かったのですが。
struct MailInputView: View {
var body: some View {
TextField("メールアドレス", text: $email)
.font(.body)
.keyboardType(.emailAddress)
.padding(.horizontal, 8)
.frame(height: 48)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(.gray, lineWidth: 1)
)
+ .contentShape(.rect)
+ .onTapGesture {
+ focusedField = .email
+ }
.padding()
.focused($focusedField, equals: .email)
}
}
これで直感的にTextFieldが反応するようになりました。
おまけ
加えてですが、TextFieldの外をタップしたら、フォーカスを外すというのも欲しい動作です。
これはSwiftUIだとサラッと実現できました。
var body: some View {
VStack {
// …
}
.onTapGesture {
focusedField = nil
}
}
このようにonTapGestureを指定してあげると、いい感じにフォーカスが外れました。
(了)
Discussion
TextFieldの枠をoverlayではなく、
textFieldStyleで実現できます。そうすることで、タップ範囲の懸念もonTapGestureの実装も不要かと思います。
自分のタップした感覚では問題なさそうに見えましたが、これでもタップ範囲が狭く感じる場合は、記事の通りの実装などを検討した方がいいかもです 🙏