【问题标题】:How to manage Scrollview Height according to textview content SwiftuiSwiftui如何根据textview内容管理Scrollview Height
【发布时间】:2021-04-29 05:09:54
【问题描述】:

我正在尝试根据 textview 内容高度与其他视图管理滚动视图高度。

代码:

struct TextviewWithScrollview: View {
    @State private var textStyle = UIFont.TextStyle.body
    @State private var textForTextView = "fdgfhjdsgfdhsgfdsfg dsfg dsfgdsfh fh sf hdsjklf dhsjkfhsdjkfdhsjkfadhsfkds fdshfjkldsh fjkldsh fdshfdshfdsfhsfdsfh sf ewf g iuf herjkdsjkjvdhsvdshvdsv dshv ds vads vds hvsdvjkds vds hviuds  vhv disu ghdisuv g"
    var body: some View {
        ZStack {
            Color.red
                .ignoresSafeArea()
            ScrollView {
                VStack(alignment: .leading) {
                    TextView(isEditable: .constant(false), text:  .constant(textForTextView), textStyle:$textStyle, didStartEditing: .constant(false),placeHolderText:"")
                }
                
                HStack {
                    Button("Top") {
                    }
                    Button("Middle") {
                        
                    }
                    Button("Bottom") {
                    }
                }
            }
        }
    }
}

struct TextView: UIViewRepresentable {
    @Binding var isEditable:Bool
    @Binding var text: String
    @Binding var textStyle: UIFont.TextStyle
    @Binding var didStartEditing: Bool
    var placeHolderText: String = ""
    
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.delegate = context.coordinator
        textView.font = UIFont.preferredFont(forTextStyle: textStyle)
        textView.autocapitalizationType = .sentences
        textView.isSelectable = true
        textView.isUserInteractionEnabled = true
        textView.isScrollEnabled = true
        textView.dataDetectorTypes = .all
        textView.textColor = .white
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = text
        uiView.font = UIFont.preferredFont(forTextStyle: textStyle)
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator($text)
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        var text: Binding<String>
        
        init(_ text: Binding<String>) {
            self.text = text
        }
        
        func textViewDidChange(_ textView: UITextView) {
            DispatchQueue.main.async {
                self.text.wrappedValue = textView.text
            }
        }
    }
}

不带滚动视图的输出:

滚动视图输出:

有人可以向我解释如何根据 textview 内容和其他人的观点来管理 Scrollview 高度。我已经尝试按照上面的方法实现,但还没有结果。

任何帮助将不胜感激。

提前致谢。

【问题讨论】:

  • 顺便说一句,如果你不需要支持 iOS 13,你应该使用TextEditor
  • 不太清楚你想要实现什么。如果文本超出屏幕怎么办?按钮应该始终在屏幕上吗?在中心?为什么要使用 UITextView,这是必需的限制吗?您能否详细说明目标。
  • @Asperi 我的目标是使用 textview 和其他视图进行全屏滚动。因为当我使用带有滚动视图的文本视图时,文本视图无法正常工作,但是当我不使用滚动视图时,文本视图工作正常,但其他视图滚动关闭。那么你能帮我如何用textview实现全屏滚动视图吗?
  • @aheze 但在 TextEditor 中不支持突出显示 url。
  • 是否可以管理滚动视图高度? @Asperi

标签: swiftui textview uiscrollview scrollview


【解决方案1】:

如果我对您的理解正确,这就是您想要实现的目标:

要获得此结果,请将 ScrollView 嵌入 GeometryReader 并使用框架调整 TextView 的大小。像这样:

struct TextviewWithScrollview: View {
@State private var textStyle = UIFont.TextStyle.body
@State private var textForTextView = "fdgfhjdsgfdhsgfdsfg dsfg dsfgdsfh fh sf hdsjklf dhsjkfhsdjkfdhsjkfadhsfkds fdshfjkldsh fjkldsh fdshfdshfdsfhsfdsfh sf ewf g iuf herjkdsjkjvdhsvdshvdsv dshv ds vads vds hvsdvjkds vds hviuds  vhv disu ghdisuv g"
var body: some View {
    ZStack {
        Color.red
            .ignoresSafeArea()
        GeometryReader { geo in
            ScrollView {
                VStack(alignment: .leading) {
                    TextView(isEditable: .constant(false), text:  .constant(textForTextView), textStyle:$textStyle, didStartEditing: .constant(false),placeHolderText:"")
                        .frame(width: geo.size.width, height: 300)
                }
                HStack {
                    Button("Top") {
                    }
                    Button("Middle") {
                    }
                    Button("Bottom") {
                    }
                }
            }
        }
    }
}

【讨论】:

  • 抱歉回复晚了。我检查了你的代码,它工作正常。但是如果我设置 textview 滚动关闭,我会停留在最后一点。因为在屏幕上启用了当前 2 滚动,一个 id scrollview 和第二个是 textview 滚动。你能帮我么。如何禁用 textview 滚动。
【解决方案2】:

这是另一种解决方案,它根据显示的文本量添加 TextView 的自动调整大小:

下面是代码:

class myTextObject: ObservableObject {
    @Published var text: String = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem."
}

struct TextviewWithScrollview: View {
    @State private var textStyle = UIFont.TextStyle.body
    
    @StateObject var textForView = myTextObject()
    @State private var textViewSize: CGSize = CGSize(width: 300, height: 300)
    
    var body: some View {
        ZStack {
            Color.red
                .ignoresSafeArea()
            
            GeometryReader { geo in
                ScrollView {

                    VStack(alignment: .leading) {
                        TextView(
                            isEditable: .constant(false),
                            text: $textForView.text,
                            textStyle: $textStyle,
                            didStartEditing: .constant(false),
                            placeHolderText: "",
                            textViewSize: $textViewSize
                        )
                        .frame(minHeight: 30, idealHeight: min(textViewSize.height, geo.size.height), maxHeight: geo.size.height)
                    }
                    
                    HStack {
                        Button("Top") {
                        }
                        Button("Middle") {
                            self.$textForView.text.wrappedValue += "\n-- a new line --"
                        }
                        Button("Bottom") {
                        }
                    }
                }
            }
        }
    }
}

struct TextView: UIViewRepresentable {
    @Binding var isEditable:Bool
    @Binding var text: String
    @Binding var textStyle: UIFont.TextStyle
    @Binding var didStartEditing: Bool
    var placeHolderText: String = ""
    
    @Binding var textViewSize: CGSize
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.delegate = context.coordinator
        textView.font = UIFont.preferredFont(forTextStyle: textStyle)
        textView.autocapitalizationType = .sentences
        textView.isSelectable = true
        textView.isUserInteractionEnabled = true
        textView.isScrollEnabled = true
        textView.dataDetectorTypes = .all
        textView.textColor = .gray
        DispatchQueue.main.async {
            textViewSize = textView.sizeThatFits(textView.textContainer.size)
        }
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = text
        uiView.font = UIFont.preferredFont(forTextStyle: textStyle)
        
        DispatchQueue.main.async {
            let newContentSize = uiView.sizeThatFits(uiView.textContainer.size)
            context.coordinator.parent.$textViewSize.wrappedValue = newContentSize
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        var parent: TextView
        
        init(parent: TextView)  {
            self.parent = parent
        }
        
        func textViewDidChange(_ textView: UITextView) {
            
            DispatchQueue.main.async {
                self.parent.$text.wrappedValue = textView.text
                
                let newContentSize = textView.sizeThatFits(textView.textContainer.size)
                self.parent.$textViewSize.wrappedValue = newContentSize
            }
        }
    }
}

【讨论】:

  • 抱歉回复晚了。我检查了你的代码,它工作正常。但是如果我设置 textview 滚动关闭,我会停留在最后一点。因为在屏幕上启用的当前 2 滚动第一个是滚动视图,第二个是文本视图滚动。你能帮我么。如何禁用 textview 滚动。
  • 不确定您想要完成什么?在我发布的第二个实现中,文本视图是自动调整大小的,因此只要文本视图适合滚动视图的可见屏幕区域,文本视图中就不会发生任何滚动。在您放入更多文本的那一刻,文本视图会提供滚动行为。您可以通过更改 .frame 修饰符中的 geo.size.height 来更改文本视图不滚动的高度。顺便说一句,当我设置 textView.isScrollEnabled = false 时,ScrollView 的行为会有所不同。我还没有研究为什么会这样。
【解决方案3】:

为文本视图设置宽度约束,并在视图顶部设置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
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-19
    • 1970-01-01
    相关资源
    最近更新 更多