お題
今日もSwiftUIに丸腰で挑んでいます。間違いには屈しない。
Listの各セルにButtonを表示して、Listのセルをタップすればなにかする、というパターン
List {
ForEach(要素一式, id: ) { 要素 in
Button(action: {
タップされたらすること
モーダルシートが表示されているかどうかのフラグ切り替え
}) {
Buttonに表示するもの
}
}
}
}
さて、タップされたときにモーダルシートを表示させたいとき、
.sheet(isPresented: フラグ) {
表示するView
}
はどこへつけるべきか?
付ける位置としては
- Button
- ForEachの外側
- List
の3択。
有力なのは1つ目のButton。各セルに対し、ForEachでButtonを生成しているので、モーダルシートを表示する処理も一緒に書くのは自然な感じがします。
実験
まずは素直に書いてみてシミュレーションで実行してみます。
セルをタップしたならば、
Warning: Attempt to present <なんたかかんたら> on <ほにゃらら> which is already presenting <うんぬん>
という警告が数十回発生しました。
適当な推測ですが、セルをタップしたときにすべてのセルでモーダルシートを表示する処理が走っているのではないでしょうか。
一回モーダルを開いているのに更に開こうとして、「もう表示してまっせ」となっているようです。「モーダルシートが表示されているかどうかのフラグ」が切り替えられたという情報が一斉に各Buttonに及んでいるように見えます。
Listの方へ付け替えて再度実行してみると、今度は警告が出ませんでした。
まとめ
単体でButtonを生成するときはモーダルシートを表示する処理をButtonにつければいいと思います。Listのセル要素としてButtonを使うときは、Listの方につけたほうがいい場合がありそうです。(設計・実装次第)
もしくは、Listの各セルを一つのViewとして切り出して、「モーダルシートが表示されているかどうかのフラグ」を各セルそれぞれに持たせるかですかね。