如何根据textview内容管理Scrollview Height Swiftui

How to manage Scrollview Height according to textview content Swiftui

我正在尝试根据其他视图的文本视图内容高度来管理滚动视图高度。

代码:

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
            }
        }
    }
}

没有滚动视图的输出:

使用滚动视图输出:

有人可以向我解释如何根据文本视图内容和其他视图来管理 Scrollview 高度。我已经尝试通过上面实现但还没有结果。

如有任何帮助,我们将不胜感激。

提前致谢。

如果我没理解错的话,这就是你想要实现的目标:

要获得此结果,请将 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 的大小:

这里是代码:

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
            }
        }
    }
}

为文本视图设置宽度限制并在视图顶部设置 GeometryReader

之所以设置GeometryReader在顶部,是因为在scroll view里面是不允许full scroll的。

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)
            }
        }
    }
}