【问题标题】:How to set width of editable UITextView in SwiftUI ScrollView?如何在 SwiftUI ScrollView 中设置可编辑 UITextView 的宽度?
【发布时间】:2021-06-16 20:43:43
【问题描述】:

我正在构建一个 SwiftUI 应用程序,我想将一个可编辑的 UITextView(包装在 UIViewRepresentable 中)放入一个 SwiftUI ScrollView。这样做的原因是我想将其他 SwiftUI 内容放在文本上方,并且我希望它与文本一起滚动。我需要一个 TextView,因为我想要富文本和工具栏。

我以为我可以禁用 UITextView 上的滚动并赋予它无限的高度,但这也赋予它无限的宽度,因此屏幕边缘的文本水平滚动,直到添加换行符。我已尝试按照How to disable vertical scrolling in UITextView? 等帖子中的建议将 textview 的内容大小和框架大小设置为屏幕宽度,但我无法使其工作。我可以成功更新 textview 内容大小,但更改似乎稍后会被覆盖(请参阅 textViewDidChange 中的打印语句)。

有什么方法可以实现吗?即 SwiftUI ScrollView 中的可编辑 UITextView。提前致谢!


import SwiftUI


struct TextView: UIViewRepresentable {
    var attributedString: NSAttributedString
    var fixedWidth: CGFloat
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }
    
    
    class Coordinator: NSObject, UITextViewDelegate {
        var parent: TextView
        
        init(_ parent: TextView) {
            self.parent = parent
        }
        
        func textViewDidChange(_ textView: UITextView) {
            print("pre content size update: \(textView.contentSize)") // width is over limit
            let newSize = textView.sizeThatFits(CGSize(width: parent.fixedWidth, height: CGFloat.greatestFiniteMagnitude))
            textView.contentSize = CGSize(width: max(newSize.width, parent.fixedWidth), height: newSize.height)
            print("post content size update: \(textView.contentSize)") // width is updated
        }
    }
    
    
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView(frame: .zero)
        textView.isEditable = true
        textView.isScrollEnabled = false
        textView.backgroundColor = .cyan // just to make it easier to see
        textView.delegate = context.coordinator
        return textView
    }
    
    func updateUIView(_ textView: UITextView, context: Context) {
        textView.attributedText = self.attributedString
        
    }
}





struct ContentView: View {
    var body: some View {
        GeometryReader { geo in
            ScrollView(.vertical) {
                VStack(alignment: .leading, spacing: /*@START_MENU_TOKEN@*/nil/*@END_MENU_TOKEN@*/){
                    //Other content
                    Image(systemName: "photo")
                        .font(.largeTitle)
                    Button("A button"){
                        print("i'm a button")
                    }
                    
                    //Editable textview
                    TextView(attributedString: NSAttributedString(string: "Here is a long string as you can see it is not wrapping but instead scrolling off the edge of the screen"), fixedWidth: geo.size.width)
                        .frame(width: geo.size.width)
                        .frame(maxHeight: .infinity)
                    
                }
                .padding(.horizontal)
            }
        }
        
    }
}

我尝试过的其他一些事情:

  • 仅使用普通的可滚动文本视图并将我的所有内容作为文本附件放入 NSAttributed 字符串中 -> 对我的内容而言过于严格并且难以检测到用户交互
  • 在 updateUIView() 中为 textview 设置锚约束 -> 当文本为空时效果很好,但如果屏幕已经加载了文本,那么父视图的布局将完全重新排列
  • How to use an NSAttributedString with a ScrollView in SwiftUI? -> 那样将一个绑定从父级传递到textview 的高度和宽度是行不通的。我认为问题不像最初出现的那样相似 - 我想为可编辑文本设置固定大小,而这个问题想要为不可编辑文本设置可调整的内容大小

【问题讨论】:

  • 你好有什么解决办法吗?
  • 对不起,我从来没有想到这一点。最后,我进行了设置,以便在编辑 uitextview 时进入“全屏”状态 - 当键盘出现时,它上面的其他 swiftui 内容就会消失。这样我就不必处理与 uitextview 一起滚动的 swiftui 内容。它是一种解决方法,但它看起来像一个功能

标签: ios swift swiftui uiscrollview uitextview


【解决方案1】:

为文本视图设置宽度约束,并在视图顶部设置GeometryReader

之所以在顶部设置GeometryReader,是因为在滚动视图内部它不允许完全滚动。

UIViewRepresentable Text View

struct TextView: UIViewRepresentable {
    var attributedString: NSAttributedString
    var fixedWidth: CGFloat
    
    let textView = UITextView(frame: .zero)
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }
    
    
    class Coordinator: NSObject, UITextViewDelegate {
        var parent: TextView
        init(_ parent: TextView) {
            self.parent = parent
        }
    }
    
    func makeUIView(context: Context) -> UITextView {
        textView.isEditable = true
        textView.isScrollEnabled = false
        textView.backgroundColor = .cyan // just to make it easier to see
        textView.delegate = context.coordinator
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.widthAnchor.constraint(equalToConstant: fixedWidth).isActive = true //<--- Here
        return textView
    }
    
    func updateUIView(_ textView: UITextView, context: Context) {
        DispatchQueue.main.async { //<--- Here
            textView.attributedText = self.attributedString
        }
    }
}

ContentView

struct ContentView: View {
    
    @State private var textViewSize: CGSize = CGSize()
    
    var body: some View {
        GeometryReader { geo in //<--- Here
            ScrollView(.vertical) {
                VStack(alignment: .leading, spacing: 0){
                    //Other content
                    Image(systemName: "photo")
                        .font(.largeTitle)
                    Button("A button"){
                        print("i'm a button")
                    }
                    
                    TextView(attributedString: NSAttributedString(string: "Here is a long string as you can see it is not wrapping but instead scrolling off the edge of the screenHere is a long string as you can see it is not wrapping but instead scrolling off the edge of the screenHere is a long string as you can see it is not wrapping but instead scrolling off the edge of the screenHere is a long string as you can see it is not wrapping but instead scrolling off the edge of the screenHere is a long string as you can see it is \n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new line\n1new lineinstead scrolling off the edge of the screenHere is a long string as you can see it is not wrapping but instead scrolling off the edge of the screenHere is a long string as you can see it is not wrapping but instead scrolling off the edge of the screen ------end"), fixedWidth: geo.size.width - 15 * 2) //<--- Here minus the padding for both size
                }.padding(.horizontal, 15)
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 2011-05-07
    • 2023-03-16
    • 2023-03-19
    • 1970-01-01
    相关资源
    最近更新 更多