如何根据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)
}
}
}
}
我正在尝试根据其他视图的文本视图内容高度来管理滚动视图高度。
代码:
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)
}
}
}
}