如何让SwiftUI List的删除按钮正常工作或隐藏?
问题根因
你遇到的问题核心是 @AppStorage 原生不支持监听自定义 Codable 数组的轻量变更:点击删除按钮触发的删除操作属于轻量修改,不会被@AppStorage捕获触发视图刷新,所以看起来无响应;而左划到底的强制删除、移动操作的变更会被系统强制触发视图刷新,所以功能正常。
解决方案
方案1:改用@State + 手动持久化
如果你的数据不需要跨页面跨App同步,直接替换@AppStorage为@State,手动做持久化即可:
struct ContentView: View { @State var conversions: [IDLine] = [] // 启动时读取本地存储的数据 init() { guard let data = UserDefaults.standard.data(forKey: "savedConversions"), let savedList = try? JSONDecoder().decode([IDLine].self, from: data) else { return } _conversions = State(initialValue: savedList) } // 数据变更后手动写入本地 private func saveToLocal() { guard let data = try? JSONEncoder().encode(conversions) else { return } UserDefaults.standard.set(data, forKey: "savedConversions") } func deleteConversion(at offsets: IndexSet) { conversions.remove(atOffsets: offsets) saveToLocal() } func moveConversion(from source: IndexSet, to dest: Int) { conversions.move(fromOffsets: source, toOffset: dest) saveToLocal() } // 其余body等代码保持不变 }
方案2:给@AppStorage做自定义适配
如果要保留@AppStorage的用法,就把自定义数组转成@AppStorage支持的Data类型存储:
struct ContentView: View { // 改用Data类型做AppStorage存储 @AppStorage("savedConversions") var conversionsData: Data = Data() // 计算属性做类型转换 var conversions: [IDLine] { get { (try? JSONDecoder().decode([IDLine].self, from: conversionsData)) ?? [] } set { conversionsData = (try? JSONEncoder().encode(newValue)) ?? Data() } } // 其余代码、删除移动方法都不用改,直接操作conversions即可 }
额外排查点
如果改完还是有问题,检查你的List行是否添加了自定义的onTapGesture等点击手势,自定义手势默认优先级高于系统删除按钮的点击手势,会导致点击无响应,可调整手势优先级或者删除冲突手势即可。
内容的提问来源于stack exchange,提问作者MarkAurelius
相关产品推荐
相关产品推荐

