SwiftUI中如何持久化保存拖拽后餐桌图形的位置?
在SwiftUI中持久化餐桌位置的解决方案
要解决关闭应用后餐桌位置重置的问题,核心是持久化每个餐桌的位置数据,下面是具体实现步骤和代码示例:
1. 定义可序列化的餐桌模型
首先创建一个符合Identifiable和Codable的Table结构体,用来存储餐桌的ID、位置和尺寸:
// 扩展CGPoint使其支持Codable(Swift默认不支持) extension CGPoint: Codable { enum CodingKeys: String, CodingKey { case x, y } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(x, forKey: .x) try container.encode(y, forKey: .y) } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) x = try container.decode(CGFloat.self, forKey: .x) y = try container.decode(CGFloat.self, forKey: .y) } } struct Table: Identifiable, Codable { let id = UUID() var position: CGPoint let size: CGSize = CGSize(width: 80, height: 80) // 可根据需求改为可配置属性 }
2. 创建数据管理类
用ObservableObject实现一个TableManager,负责餐桌数据的增删改、持久化存储和加载:
class TableManager: ObservableObject { @Published var tables: [Table] = [] private let defaultsKey = "RestaurantSavedTables" // 初始化时加载已保存的数据 init() { loadSavedTables() } // 从UserDefaults加载数据 private func loadSavedTables() { guard let data = UserDefaults.standard.data(forKey: defaultsKey), let savedTables = try? JSONDecoder().decode([Table].self, from: data) else { return } tables = savedTables } // 保存数据到UserDefaults func saveTables() { guard let data = try? JSONEncoder().encode(tables) else { return } UserDefaults.standard.set(data, forKey: defaultsKey) } // 添加新餐桌 func addTable(at position: CGPoint) { tables.append(Table(position: position)) saveTables() } // 更新餐桌位置 func updateTablePosition(for table: Table, newPosition: CGPoint) { guard let index = tables.firstIndex(where: { $0.id == table.id }) else { return } tables[index].position = newPosition saveTables() } }
3. 实现视图与拖拽交互
在主视图中使用TableManager,绑定拖拽手势更新位置并触发保存:
struct RestaurantPlanView: View { @StateObject private var tableManager = TableManager() var body: some View { ZStack { // 餐厅平面图背景(示例) Color.gray.opacity(0.1) .ignoresSafeArea() // 渲染所有餐桌 ForEach($tableManager.tables) { $table in Rectangle() .fill(Color.blue) .frame(width: table.size.width, height: table.size.height) .position(table.position) .gesture( DragGesture() .onChanged { value in // 拖拽过程中实时更新位置 table.position = value.location } .onEnded { _ in // 拖拽结束后保存所有数据 tableManager.saveTables() } ) } // 添加餐桌按钮(示例:点击在屏幕中央添加) Button("添加餐桌") { let centerPos = CGPoint( x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY ) tableManager.addTable(at: centerPos) } .position(x: 80, y: 80) .buttonStyle(.borderedProminent) } } }
补充说明
- 如果你的应用需要管理大量餐桌或更复杂的属性(如餐桌编号、座位数),建议用Core Data替代
UserDefaults,避免存储大量数据的性能问题。 - 拖拽时的保存时机可以优化:比如用
debounce减少保存频率,避免频繁写入存储,但简单场景下拖拽结束后直接保存足够实用。
内容的提问来源于stack exchange,提问作者Samuele Segrini
相关产品推荐
相关产品推荐

