【问题标题】:SwiftUI TextEditor - save the state after completion of editingSwiftUI TextEditor - 编辑完成后保存状态
【发布时间】:2021-01-30 09:40:54
【问题描述】:

问题概述

我正在构建一个笔记应用程序,并且有一个笔记编辑视图,其中一些 TextEditor 用于听取用户的输入。现在一个环境对象被传递给这个笔记编辑视图,我设计了一个保存按钮来保存更改。它运行良好,只是用户必须单击保存按钮才能更新模型。

预期行为

一旦编辑完成,文本编辑器将更新 EnvironmentObject 实例的值。不一定要点击保存按钮来保存更改。

下面是view的示例代码

struct NoteDetails: View {

    @EnvironmentObject var UserData: Notes
    @Binding var selectedNote: SingleNote?
    @Binding var selectedFolder: String?
    @Binding var noteEditingMode: Bool

    @State var title:String = ""
    @State var updatedDate:Date = Date()
    @State var content: String = ""
    
    var id: Int?
    var label: String?
    
    @State private var wordCount: Int = 0

 var body: some View {

VStack(alignment: .leading) {
                TextEditor(text: $title)
                    .font(.title2)
                    .padding(.top)
                    .padding(.horizontal)
                    .frame(width: UIScreen.main.bounds.width, height: 50, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                   
                    
                
                                        
                Text(updatedDate, style: .date)
                    .font(.subheadline)
                    .padding(.horizontal)
                
                Divider()
                
                TextEditor(text: $content)
                    .font(.body)
                    .lineSpacing(15)
                    .padding(.horizontal)
                    
                    .frame(maxHeight:.infinity)
                    

                Spacer()
                
            }
}
}

下面是EnvironmentObject的edit func的示例代码

UserData.editPost(label: label!, id: id!, data: SingleNote(updateDate: Date(), title: title, body: content))

我尝试过的方法

  • 我尝试将 onChange 修饰符添加到 TextEditor,但它会在发生任何更改时立即应用,这是不希望的。我还尝试了其他一些修饰符,例如 onDisapper 等。
  • 用户数据有 @Published var NoteList: [String: [SingleNote]],我尝试将 $UserData.NoteList[label][id].title 传递给 TextEditor,但也没有被接受

在互联网上没有找到合理的解决方案,所以在这里提出这个问题。提前感谢您的建议!

【问题讨论】:

    标签: swiftui text-editor


    【解决方案1】:

    我不知道编辑完成后要保存的确切含义。以下是我发现的两种可能的方法。

    注意: 在下面的演示中,蓝色背景的文本显示保存的文本。

    1。当用户关闭键盘时保存

    解决方案:添加点击手势,让用户在TextEditor 之外点击时关闭键盘。同时拨打save()

    代码:

    struct ContentView: View {
        
        @State private var text: String = ""
        @State private var savedText: String = ""
        
        
        var body: some View {
            VStack(spacing: 20) {
                Text(savedText)
                    .frame(width: 300, height: 200, alignment: .topLeading)
                    .background(Color.blue)
                
                TextEditor(text: $text)
                    .frame(width: 300, height: 200)
                    .border(Color.black, width: 1)
                    .onTapGesture {}
            }
            .onTapGesture { hideKeyboardAndSave() }
        }
        
        
        private func hideKeyboardAndSave() {
            UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
            save()
        }
        
        
        private func save() {
            savedText = text
        }
    }
    

    2。在 x 秒内没有更改后保存

    解决方案:使用 Combine.debounce 仅在 x 秒过去且没有进一步事件后进行发布和观察。

    我已将x 设置为 3。

    代码:

    struct ContentView: View {
        
        @State private var text: String = ""
        @State private var savedText: String = ""
        
        let detector = PassthroughSubject<Void, Never>()
        let publisher: AnyPublisher<Void, Never>
        
        init() {
            publisher = detector
                .debounce(for: .seconds(3), scheduler: DispatchQueue.main)
                .eraseToAnyPublisher()
        }
        
        
        var body: some View {
            VStack(spacing: 20) {
                Text(savedText)
                    .frame(width: 300, height: 200, alignment: .topLeading)
                    .background(Color.blue)
                
                TextEditor(text: $text)
                    .frame(width: 300, height: 200)
                    .border(Color.black, width: 1)
                    .onChange(of: text) { _ in detector.send() }
                    .onReceive(publisher) { save() }
            }
        }
        
        
        private func save() {
            savedText = text
        }
    }
    

    【讨论】:

    • 感谢您的建议!它有很大帮助!我应该更清楚,例如,我在 iPhone 上查看 Apple 制作的 Native Notes 应用程序,每当您在便笺中键入内容时,它都会立即保存。你知道那个解决方案是什么吗?这与您的第二个解决方案相似吗?
    • 有点上下文,对不起,这是一个子视图导航链接,如何在用户单击按钮返回时自动保存更改。它可以简化场景。
    • 欢迎您!是的,我认为这会简化场景。保存在 .onDisappear 里面对我来说可以吗?
    • 我从来没有做过类似的事情,但看起来 Apple Notes 可能会使用与我的第二个类似的解决方案。
    • 直观地说,onDisappear 是正确的选择,对吧?我尝试在下面添加这样的修饰符。但是它弹出了一个奇怪的错误,说 is null 所以当我点击它时 unwrap 失败。这很奇怪,因为只要选择了 id 就不能为空,并且在父导航视图中,id 已传递给该视图并且为空。 swift onDisappear(perform: { UserData.NoteList[label!]![id!].title = title }) onDisappear 修饰符中的环境对象应该如何处理?你能建议吗?谢谢!