ListはNavigationLinkやButtonを置くとList行全体がタップ範囲になりますが、
TextやImageなどを置いた場合はコンテンツのみがタップ範囲になります。
UIや機能の作り方次第では不便になったり、最悪タップ不可な状態も出来るので気を付けましょう。
空白を含める方法
List {
HStack {
Text("")
Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
}
}
この様にHStack、Spacer、contentShapeを組み合わせることでList行全体がタップ範囲となります。
SwiftUIはコンテンツの描画範囲がタップ可能になります。
Spacerなどの余白は自動的にタップ範囲から除外されます。
Textだけでは文字がないのでコンテンツの描画領域が無くタップ出来ませんでしたが、
リスト行全体がコンテンツの扱いとなった為タップ出来るようになりました。
HStackとSpacerで横範囲全体を指定し、contentShapeでコンテンツ領域に含む設定をしてる為、どれかが欠けるとList行全体にはなりません。
実用例
ありがちなUIでタップ範囲に空白を含めないと使いにくくなる例を紹介します。
ListでNavigationLinkが並んでおり、EditModeでタップするとSheetが開き項目名が編集出来る例です。
struct ListTapView: View {
@Environment(\.editMode) var editMode
@State var text = "Item"
@State var sheet = false
var body: some View {
NavigationView{
List{
if editMode?.wrappedValue == .inactive {
NavigationLink(text,destination: Text(text))
}else {
HStack{
Text(text)
Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
sheet = true
}
}
if editMode?.wrappedValue == .inactive {
NavigationLink(text,destination: Text(text))
}else {
Text(text).onTapGesture {
sheet = true
}
}
}
.sheet(isPresented: $sheet){
Form{
TextField("",text: $text)
}
}
.navigationTitle("ListTap")
.toolbar{
ToolbarItem(placement: .navigationBarTrailing){
EditButton().environment(\.editMode, editMode)
}
}
}
}
}
まず初めに、NavigationLinkはEditModeではタップ出来ない為、
EditModeで表示分けする必要があります。
EditModeではButtonも動作しない為TextにonTapGestureを付けます。
この時に余白も含める事でNavigationLinkが表示されている際と同じタップ範囲にします。
上下2つのList行で操作感を比較してみて下さい。
特に文字数が少ないとタップ範囲が狭く操作感が悪くなります。
また今回はテキストを自由にユーザー入力可能にしました。
余白を含まない場合はユーザーが空白に設定してしまうとタップ不可になります。
余談
NavigationLinkにonTapGestureをつけるとどうなるか?
答えはonTapGestureが優先されます。
常にonTapGestureが有効になり、onTapGestureの範囲外のみNavigationLinkとして動作します。
今回の様なEditModeで切り替えたいと言った場合には向きません。
しかし有効活用できる場合もあります。
NavigationLinkのラベルの一部のみをボタンの様にして扱う場合にはこの使用が重宝します。
以下のアプリで使っているので興味があったら確認してみて下さい。
コメント