🧝♂️
NavigationStackの中でEditButtonを使うと、editModeが正しく取得できない
Listの並び替えや削除などに使用するEditButton()
ですが、環境変数のeditMode
を使用して現在の編集状態を取得しようとしたところ、NavigationStack
内でEditButton
を使用するケースだとeditMode
が正しく反映されていないことが分かった。
環境
- Xcode 14.2
- iOS 16.2
原因発生例
コード
import SwiftUI
struct ContentView: View {
@Environment(\.editMode) var editMode
private var isActiveEditing: Bool {
return editMode?.wrappedValue == .active
}
var body: some View {
VStack {
NavigationStack {
List {
ForEach(0..<5) { number in
Text(String(number))
}
.onMove(perform: moveItem)
}
.navigationTitle("List")
.toolbar {
EditButton()
}
}
// editModeの状態によって変化する
Text(isActiveEditing ? "アクティブ" : "インアクティブ")
.foregroundColor(isActiveEditing ? .accentColor : .gray)
}
}
private func moveItem(from source: IndexSet, to destination: Int) {
print("moveItem")
}
}
結果
EditButton()
でリストは編集中のUIに切り替わるが、editMode
で値で切り替わる下部のテキストはずっとインアクティブのままです。
NavigationStack外だとリストが編集中に切り替わらない
コード
var body: some View {
VStack {
NavigationStack {
List {
ForEach(0..<5) { number in
Text(String(number))
}
.onMove(perform: moveItem)
}
.navigationTitle("List")
}
// NavigationStack外に出す
EditButton()
// editModeの状態によって変化する
Text(isActiveEditing ? "アクティブ" : "インアクティブ")
.foregroundColor(isActiveEditing ? .accentColor : .gray)
}
}
結果
NavigationStack
外にEditButton()
を出して試してみると、editMode
の値の変化は取得出来るが今度はリストが編集状態にならない。
解決策
あまりやりたくないですが、EditButton()
と同様の振る舞いをするEditButton
を作成することで解決します。
EditButton
// 自家製のEditButton
struct EditButton: View {
@Binding var editMode: EditMode
var body: some View {
Button(editMode.isEditing ? "Done" : "Edit") {
switch editMode {
case .active:
editMode = .inactive
case .inactive:
editMode = .active
default:
break
}
}
}
}
コード
クラス変数として記述していた環境変数を@State
変数に変更して、Button操作によってその値を変更しています。
また、リストの編集状態を変更する為に、environment
モディファイアを使い、環境変数側のeditMode
も切り替えています。
struct ContentView: View {
@State private var editMode: EditMode = .inactive
private var isActiveEditing: Bool {
return editMode == .active
}
var body: some View {
VStack {
NavigationView {
List {
ForEach(0..<5) { number in
Text(String(number))
}
.onMove(perform: moveItem)
}
.navigationTitle("List")
.toolbar {
EditButton(editMode: $editMode)
}
.environment(\.editMode, $editMode)
}
.navigationViewStyle(.stack)
// editModeの状態によって変化する
Text(isActiveEditing ? "アクティブ" : "インアクティブ")
.foregroundColor(isActiveEditing ? .accentColor : .gray)
}
}
private func moveItem(from source: IndexSet, to destination: Int) {
print("moveItem")
}
}
結果
これで意図した動き出来るようになりました。
おわりに
SwiftUIのバグなのか?まだ確証まで至っていませんが、NavigationStack
とEditButton()
を使用するとeditMode
の値が正しく取得できなくて困ってしまいました。
今回は自家製のEdtiButton
を作成することで解決しましたが、力技なのであまりやりたくなく、もし他に簡単な対策をご存知の方いらっしゃいましたら、優しく教えていただけると嬉しいです。
参考
Discussion
私もアクティブにならずに困っていましたが、↓の記事の通りに実装したらうまく取得できました!
ありがとうございます!🙏
再度教えていただいた解決方法で試してみたいと思います!!