从不同的视图更新数组的内容 [英] Updating the contents of an array from a different view
问题描述
我正在用 Swiftui 编写一个 macOS 应用程序,适用于 Big Sur 和更新版本.这是一个三窗格导航视图应用程序,其中最左侧的窗格具有选项列表(在本例中为所有注释),中间窗格是实际项目(标题和日期)的列表,最后一个是文本编辑器,其中用户添加文本.
I'm writing a macOS app in Swiftui, for Big Sur and newer. It's a three pane navigationview app, where the left most pane has the list of options (All Notes in this case), the middle pane is a list of the actual items (title and date), and the last one is a TextEditor where the user adds text.
每个窗格都是一个视图,通过 NavigationLink
调用下一个视图.这是基本代码.
Each pane is a view that calls the the next view via a NavigationLink
. Here's the basic code for that.
struct NoteItem: Codable, Hashable, Identifiable {
let id: Int
var text: String
var date = Date()
var dateText: String {
dateFormatter.dateFormat = "EEEE, MMM d yyyy, h:mm a"
return dateFormatter.string(from: date)
}
var tags: [String] = []
}
struct ContentView: View {
@State var selection: Set<Int> = [0]
var body: some View {
NavigationView {
List(selection: self.$selection) {
NavigationLink(destination: AllNotes()) {
Label("All Notes", systemImage: "doc.plaintext")
}
.tag(0)
}
.listStyle(SidebarListStyle())
.frame(minWidth: 100, idealWidth: 150, maxWidth: 200, maxHeight: .infinity)
Text("Select a note...")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
struct AllNotes: View {
@State var items: [NoteItem] = {
guard let data = UserDefaults.standard.data(forKey: "notes") else { return [] }
if let json = try? JSONDecoder().decode([NoteItem].self, from: data) {
return json
}
return []
}()
@State var noteText: String = ""
var body: some View {
NavigationView {
List(items) { item in
NavigationLink(destination: NoteView()) {
VStack(alignment: .leading) {
Text(item.text.components(separatedBy: NSCharacterSet.newlines).first!)
Text(item.dateText).font(.body).fontWeight(.light)
}
.padding(.vertical, 8)
}
}
.listStyle(InsetListStyle())
Text("Select a note...")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
.navigationTitle("A title")
.toolbar {
ToolbarItem(placement: .navigation) {
Button(action: {
NewNote()
}) {
Image(systemName: "square.and.pencil")
}
}
}
}
struct NoteView: View {
@State var text: String = ""
var body: some View {
HStack {
VStack(alignment: .leading) {
TextEditor(text: $text).padding().font(.body)
.onChange(of: text, perform: { value in
print("Value of text modified to = \(text)")
})
Spacer()
}
Spacer()
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.white)
}
}
创建新笔记时,如何将用户在NoteView
中的TextEditor
上添加的文本保存在AllNotes
中加载的数组中> 这样我就可以保存新文本了吗?理想情况下,有一个 SaveNote()
函数会在 TextEditor .onChange 上发生.但同样,鉴于数组位于 AllNotes
中,我如何从其他视图更新它?
When I create a new note, how can I save the text the user added on the TextEditor
in NoteView
in the array loaded in AllNotes
so I could save the new text? Ideally there is a SaveNote()
function that would happen on TextEditor .onChange. But again, given that the array lives in AllNotes
, how can I update it from other views?
感谢您的帮助.新手来了!
Thanks for the help. Newbie here!
推荐答案
在应用中使用EnvironmentObject
use EnvironmentObject in App
import SwiftUI
@main
struct NotesApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(DataModel())
}
}
}
现在DataModel是一个符合ObservableObject的类
now DataModel is a class conforming to ObservableObject
import SwiftUI
final class DataModel: ObservableObject {
@AppStorage("notes") public var notes: [NoteItem] = []
}
任何与数据相关的东西都应该在 DataModel 中而不是在 View 中完成,而且您可以从任何地方访问和更新它,在您的 ContentView 或任何子视图中像这样声明
any data related stuff should be done in DataModel not in View, plus you can access it and update it from anywhere, declare it like this in your ContentView or any child View
笔记视图
import SwiftUI
struct NoteView: View {
@EnvironmentObject private var data: DataModel
var note: NoteItem
@State var text: String = ""
var body: some View {
HStack {
VStack(alignment: .leading) {
TextEditor(text: $text).padding().font(.body)
.onChange(of: text, perform: { value in
guard let index = data.notes.firstIndex(of: note) else { return }
data.notes[index].text = value
})
Spacer()
}
Spacer()
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.white)
.onAppear() {
print(data.notes.count)
}
}
}
AppStorage 是使用 UserDefaults 的更好方法,但 AppStorage 尚不能与自定义对象一起使用(我认为它适用于 iOS 15),因此您需要添加此扩展以使其工作.
AppStorage is the better way to use UserDefaults but AppStorage does not work with custom Objects yet (I think it does for iOS 15), so you need to add this extension to make it work.
导入 SwiftUI
struct NoteItem: Codable, Hashable, Identifiable {
let id: UUID
var text: String
var date = Date()
var dateText: String {
let df = DateFormatter()
df.dateFormat = "EEEE, MMM d yyyy, h:mm a"
return df.string(from: date)
}
var tags: [String] = []
}
extension Array: RawRepresentable where Element: Codable {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode([Element].self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
}
现在我更改了 AllNotes 视图以处理新更改
Now I changed AllNotes view to work with new changes
struct AllNotes: View {
@EnvironmentObject private var data: DataModel
@State var noteText: String = ""
var body: some View {
NavigationView {
List(data.notes) { note in
NavigationLink(destination: NoteView(note: note)) {
VStack(alignment: .leading) {
Text(note.text.components(separatedBy: NSCharacterSet.newlines).first!)
Text(note.dateText).font(.body).fontWeight(.light)
}
.padding(.vertical, 8)
}
}
.listStyle(InsetListStyle())
Text("Select a note...")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.navigationTitle("A title")
.toolbar {
ToolbarItem(placement: .navigation) {
Button(action: {
data.notes.append(NoteItem(id: UUID(), text: "New Note", date: Date(), tags: []))
}) {
Image(systemName: "square.and.pencil")
}
}
}
}
}
这篇关于从不同的视图更新数组的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!