Swiftui如何根据textview内容管理Scrollview Height
Posted
技术标签:
【中文标题】Swiftui如何根据textview内容管理Scrollview Height【英文标题】:How to manage Scrollview Height according to textview content Swiftui 【发布时间】: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 【参考方案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)
【讨论】:
以上是关于Swiftui如何根据textview内容管理Scrollview Height的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 将数据从 Firebase 加载到 TextView
在 SwiftUI 中为 UITextView 设置初始视图偏移量
如何使用 SwiftUI 在 UICollectionViewCell 中填充内容
SwiftUI - 如何在运行时更改内部内容后获取 ScrollView 内容高度