SwiftUI TextEditor - 编辑完成后保存状态

Posted

技术标签:

【中文标题】SwiftUI TextEditor - 编辑完成后保存状态【英文标题】:SwiftUI TextEditor - save the state after completion of editing 【发布时间】: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,但也没有被接受

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

【问题讨论】:

【参考方案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 修饰符中的环境对象应该如何处理?你能建议吗?谢谢!

以上是关于SwiftUI TextEditor - 编辑完成后保存状态的主要内容,如果未能解决你的问题,请参考以下文章

当 TextEditor 失去焦点时如何得到通知?

如何防止 TextEditor 在 SwiftUI 中滚动?

如何根据 TextEditor 的文本更改为 SwiftUI 视图设置动画?

SwiftUI for MacOS 中的多行 TextField/TextEditor 表单

SwiftUI 4.0 如何轻松在 iOS 16 中设置 TextEditor 背景色

SwiftUI 4.0 如何轻松在 iOS 16 中设置 TextEditor 背景色