2種類の.sheet
始めにみなさんご存知かと思われますが、swiftUIでモーダル遷移させるsheetには2種類あります。それが下の2つです。
1...sheet(isPresented:onDismiss:content:)
2...sheet(item:onDismiss:content:)
大きな違いは引数が.sheet(isPresented:..)になっているか、それとも.sheet(item:..)になっているかの違いです。「isPresented」はバインディングされたBool値がtrueになることでシートを表示させ、「item」はIdentifiableプロトコルに適合した任意の型が代入されることでシートを表示させます。
つまずき
自分の理想とする挙動は、動画1のように選択された項目の値を次のViewへ渡し、TextField内で表示させることです。
しかし、.sheet(isPresented:..)のシートを使用すると、動画2のように、どの項目をタップしたとしても、最初に表示されるのは、fruitIndexの初期値である「0」番目の「りんご」が表示されてしまいます。しかし、その後、他の項目をタップすると、ちゃんと動いてくれます。
問題のコード
struct IsPresentedSheet: View {
@State private var fruits = [
Fruit(name: "りんご"),
Fruit(name: "もも"),
Fruit(name: "レモン"),
Fruit(name: "ぶどう")
]
@State private var isSheetPresented = false
@State private var fruitsIndex = 0
var body: some View {
NavigationStack{
List(fruits.indices, id: \.self) { index in
HStack{
Text(fruits[index].name)
Spacer()
Button {
fruitsIndex = index
isSheetPresented = true
} label: {
Image(systemName: "info.circle.fill")
}
}
}
.sheet(isPresented: $isSheetPresented) {
SheetView(
fruitNewItem: fruits[fruitsIndex].name
)
}
}
}
}
struct SheetView: View {
@Environment(\.dismiss) var dismiss
@State var fruitNewItem: String
var body: some View {
NavigationStack{
HStack{
Text("名前")
TextField("", text: $fruitNewItem)
.frame(width: 210,height: 50)
.border(Color.black)
.padding()
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Cancel"){
dismiss()
}
}
}
}
}
}
解決方法
1.sheet(item:onDismiss:content:)を使用する。
「item」を引数に持つsheetを使用すると、こういった挙動は改善されます。しかし、なぜこのようなな違いが出てくるのかまでは突き止めることができませんでした。理由をご存知の方がいましたら、是非ご鞭撻頂けたらと思います。
ちなみに
var body: some View直下にlet _ = print(fruitsIndex)でアクセスするか、Listのコードブロックの最後に.onChange内でfruitsIndexをprintすると、ちゃんと表示してくれることが確認できました。最初にViewが描画される時に、プロパティにアクセスすると、この謎挙動が修正されるのでしょうか?