如何在SwiftUI for MacOS中创建多行文本字段?

3
我正在使用Swift编写我的第一个MacOS应用程序。我需要创建一个简单的可编辑文本框,允许多个段落。在HTML中,这将是一个

这个回答解决了你的问题吗?如何在SwiftUI中创建多行文本框? - New Dev
@NewDev 谢谢,我已经看过了。据我所知,它需要使用UIKit,但这对于MacOS应用程序不可用。 - Manngo
1个回答

8

这里是一些像iOS14 TextEditor的组件的初始演示。

演示使用Xcode 11.7 / macOS 10.15.6进行了准备和测试。

演示

struct TestTextArea: View {
    @State private var text = "Placeholder: Enter some text"

    var body: some View {
        VStack {
            TextArea(text: $text)
                .border(Color.black)
//            Text(text) // uncomment to see mirror of enterred text
        }.padding()
    }
}

struct TextArea: NSViewRepresentable {
    @Binding var text: String

    func makeNSView(context: Context) -> NSScrollView {
        context.coordinator.createTextViewStack()
    }

    func updateNSView(_ nsView: NSScrollView, context: Context) {
        if let textArea = nsView.documentView as? NSTextView, textArea.string != self.text {
            textArea.string = self.text
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(text: $text)
    }

    class Coordinator: NSObject, NSTextViewDelegate {
        var text: Binding<String>

        init(text: Binding<String>) {
            self.text = text
        }

        func textView(_ textView: NSTextView, shouldChangeTextIn range: NSRange, replacementString text: String?) -> Bool {
            defer {
                self.text.wrappedValue = (textView.string as NSString).replacingCharacters(in: range, with: text!)
            }
            return true
        }

        fileprivate lazy var textStorage = NSTextStorage()
        fileprivate lazy var layoutManager = NSLayoutManager()
        fileprivate lazy var textContainer = NSTextContainer()
        fileprivate lazy var textView: NSTextView = NSTextView(frame: CGRect(), textContainer: textContainer)
        fileprivate lazy var scrollview = NSScrollView()

        func createTextViewStack() -> NSScrollView {
            let contentSize = scrollview.contentSize

            textContainer.containerSize = CGSize(width: contentSize.width, height: CGFloat.greatestFiniteMagnitude)
            textContainer.widthTracksTextView = true

            textView.minSize = CGSize(width: 0, height: 0)
            textView.maxSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
            textView.isVerticallyResizable = true
            textView.frame = CGRect(x: 0, y: 0, width: contentSize.width, height: contentSize.height)
            textView.autoresizingMask = [.width]
            textView.delegate = self

            scrollview.borderType = .noBorder
            scrollview.hasVerticalScroller = true
            scrollview.documentView = textView

            textStorage.addLayoutManager(layoutManager)
            layoutManager.addTextContainer(textContainer)

            return scrollview
        }
    }
}

太棒了!你真的是即兴创作出来的吗?我可以在真实项目中使用这个吗?我可以在哪里了解更多关于你所做的事情呢? - Manngo
这是一个演示。您可以随意使用或修改它。如果您的项目是开源的,并且如果您希望(有人这样做),您可以在相应的源模块中添加对此帖子的引用,但这取决于您。 - Asperi
还有一件事:我能在文本区域内添加填充吗? - Manngo
@Asperi - 你能够更新一下,让它支持完整的富文本版本,而不仅仅是纯文本吗?谢谢。 - Duncan Groenewald
@Asperi - 更好的方法是查看我的问题,因为我发布了一个链接到演示SwiftUI应用程序,它说明了在重复使用SwiftUI视图时遇到的问题。 - Duncan Groenewald
我不知道为什么,但 defer 块不允许我更改提供作为绑定的任何值。但是,删除 defer 可以解决这个问题。 - fnc12

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接