List 内で NavigationLink で isActive を使用し、 Button で isActive を管理した時に isActiveが機能しなくなることがあったので対処法を記しておきます。
Listを使用しないときの NavigationLink と Button の組み合わせ
List を使用しない場合、 NavigationLink と Button を併用し isActive の Bool値を falase で固定すると、当然ですが画面遷移は起きません。
ContentView
struct ContentView: View {
@State var openDetailView = false
var body: some View {
ZStack {
NavigationLink(
destination: DetailView,
isActive: $openDetailView,
label: { EmptyView() }
)
Button(action: {
//self.openDetailView = true
}, label: {
Text("画面遷移")
})
}
}
var DetailView: some View {
Text("DetailView")
}
}
上記のコードのListを追加する
では、上記のコードにListを追加してみます。
ContentView
struct ContentView: View {
@State var openDetailView = false
@State var selectedIndex = 0
var body: some View {
List(1..<11) { index in
ZStack {
NavigationLink(
destination: DetailView,
isActive: $openDetailView,
label: { EmptyView() }
)
Button(action: {
//self.openDetailView = true
selectedIndex = index
}, label: {
Text("\(index)の画面遷移")
})
}
}
}
var DetailView: some View {
Text("\(selectedIndex)のDetailView")
}
}
ここに List を追加すると isActive の値が false であるにも関わらず画面遷移が発生してしまします。
Listを使用した NavigationLink と Button のベストプラクティス
NavigationLink と ZStack を List の外に出すことで isActive を挙動通りに動かすことができます。
ContentView
struct ContentView: View {
@State var openDetailView = false
@State var selectedIndex = 0
var body: some View {
ZStack {
NavigationLink(
destination: DetailView,
isActive: $openDetailView,
label: { EmptyView() }
)
List(1..<11) { index in
Button(action: {
//self.openDetailView = true
selectedIndex = index
}, label: {
HStack {
Text("\(index)の画面遷移")
Spacer()
Image(systemName: "chevron.right")
}
})
}
}
}
var DetailView: some View {
Text("\(selectedIndex)のDetailView")
}
}
コメントアウトを外せば挙動通り、画面遷移が行われます。
NavigatoinView の定義
NavigationView がないと NavigationLink は機能しないので、定義する必要があります。
ContentViewで使用しても良いですし、
ContentViewで使用する場合
var body: some View {
ZStack {
NavigationLink(
destination: DetailView,
isActive: $openDetailView,
label: { EmptyView() }
)
Button(action: {
//self.openDetailView = true
}, label: {
Text("画面遷移")
})
}
}
{アプリ名}App.swift ファイルに指定してもOKです。
{アプリ名}Appの場合
@main
struct App: App {
var body: some Scene {
WindowGroup {
NavigationView {
ContentView()
}
}
}
}