SWIFT如何调整textview的高度到他的内容?
How to adjust the height of a textview to his content in SWIFT?
在我的视图控制器中,我有一个 UITextView。这个文本视图填充了一个字符串。字符串可以很短也可以很长。根据字符串的长度,文本视图的高度必须进行调整。
我使用故事板和自动布局。
我对 textview 的高度有一些问题。
有时,高度会完美地适应文本。有时,不,文本在第一行被裁剪。下面,textview 是黄色的。蓝色是滚动视图内的容器视图。紫色是拍照的地方。
文本来自我的核心数据库,它们是字符串属性。
在屏幕 1 和屏幕 2 之间,唯一改变的是字符串。
如果我在控制台中打印字符串,我就会得到正确的文本:
my amazing new title
Another funny title for demo
我的 textview 的限制:
我不明白为什么我有 2 个不同的显示器。
编辑
我尝试了@Nate 的建议,在 viewDidLoad 中,我添加了:
myTextViewTitle.text="my amazing new title"
myTextViewTitle.setContentHuggingPriority(1000, forAxis: UILayoutConstraintAxis.Vertical)
myTextViewTitle.setContentCompressionResistancePriority(1000, forAxis: UILayoutConstraintAxis.Vertical)
myTextViewTitle.setTranslatesAutoresizingMaskIntoConstraints(false)
let views = ["new_view": myTextViewTitle]
var constrs = NSLayoutConstraint.constraintsWithVisualFormat("|-8-[new_view]-8-|", options: NSLayoutFormatOptions(0), metrics: nil, views: views)
self.view.addConstraints(constrs)
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-8-[new_view]", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
self.myTextViewTitle.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[new_view(220@300)]", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
没有结果。在界面生成器中为我的文本视图添加或不添加高度限制...
编辑 2
我需要一个 UITextView 而不是 UIlabel,因为有后退按钮,才能使用排除路径。
let exclusionPathBack:UIBezierPath = UIBezierPath(rect: CGRect(x:backButton.bounds.origin.x, y:backButton.bounds.origin.y, width:backButton.bounds.width+10, height:backButton.bounds.height))
myTextViewTitle.textContainer.exclusionPaths=[exclusionPathBack]
为什么不用后退按钮的图像和文本的 UILabel,并使用自动布局来定位它们?也许还有黄色背景的第三个视图。
我找到了解决办法。
我关注的是我的 UITextView 的高度,然后我读了一篇 post 谈论纵横比的文章。我想尝试一下,结果成功了!
所以在情节提要中,我为文本视图添加了纵横比,并选中了 "Remove at build time" 选项。
在viewDidLayoutSubviews()中,我写了:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let contentSize = self.myTextViewTitle.sizeThatFits(self.myTextViewTitle.bounds.size)
var frame = self.myTextViewTitle.frame
frame.size.height = contentSize.height
self.myTextViewTitle.frame = frame
aspectRatioTextViewConstraint = NSLayoutConstraint(item: self.myTextViewTitle, attribute: .Height, relatedBy: .Equal, toItem: self.myTextViewTitle, attribute: .Width, multiplier: myTextViewTitle.bounds.height/myTextViewTitle.bounds.width, constant: 1)
self.myTextViewTitle.addConstraint(aspectRatioTextViewConstraint!)
}
完美运行。
我对一个极其相似问题的简单解决方案:
我使用了行数设置为 0 的标签,而不是尝试使用文本字段或视图。然后我将前缘和后缘剪裁到标签的容器中,在我的例子中,它们限制了它们的宽度,0 作为约束的常量。要注意的是将行数设置为 0,以允许标签根据其内容增长或收缩。对于我为宽度配置的所有不同大小 类(在我的例子中是容器宽度),文本永远不会被截断并且标签的高度永远不会超过它们的内容。针对 IOS 8.0 及更高版本进行了测试(还要确保在所有标签的 'Preferred Width' 属性旁边取消选中 'explicit',以便标签宽度根据不同大小进行调整 类)- 完美运行.
首先,禁用 UITextView 的可滚动。
两个选项:
- 取消选中在 .xib 中启用滚动。
- [TextView setScrollEnabled:NO];
创建一个 UITextView 并将其与 IBOutlet (TextView) 连接。
添加默认高度的 UITextView 高度约束,将其与 IBOutlet (TextViewHeightConstraint) 连接。
当您异步设置 UITextView 的文本时,您应该计算 UITextView 的高度并将 UITextView 的高度约束设置为它。
示例代码:
CGSize sizeThatFitsTextView = [TextView sizeThatFits:CGSizeMake(TextView.frame.size.width, MAXFLOAT)];
TextViewHeightConstraint.constant = sizeThatFitsTextView.height;
在swift 2.3:
func textViewDidChange(textView: UITextView) {
let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.max))
if size.height != TXV_Height.constant && size.height > textView.frame.size.height{
TXV_Height.constant = size.height
textView.setContentOffset(CGPointZero, animated: false)
}
}
在Swift 3.0 中,其中 tvHeightConstraint 是主题 TextView 的高度约束(如果用于多个文本视图,会将其添加到函数输入中):
func textViewDidChange(textView: UITextView) {
let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
if size.height != tvHeightConstraint.constant && size.height > textView.frame.size.height{
tvHeightConstraint.constant = size.height
textView.setContentOffset(CGPoint.zero, animated: false)
}
}
H/T @cmi 和@Pablo Ruan
我已经修改了您的代码并将其用于:布局子视图和 textViewDidChange。非常感谢你让我在一个小时的故障排除后度过了愉快的一天...
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
textViewDidChange(self.recordingTitleTV)
}
func textViewDidChange(_ textView: UITextView) {
let contentSize = textView.sizeThatFits(textView.bounds.size)
var frame = textView.frame
frame.size.height = contentSize.height
textView.frame = frame
let aspectRatioTextViewConstraint = NSLayoutConstraint(item: textView, attribute: .height, relatedBy: .equal, toItem: textView, attribute: .width, multiplier: textView.bounds.height/textView.bounds.width, constant: 1)
textView.addConstraint(aspectRatioTextViewConstraint)
}
在我的视图控制器中,我有一个 UITextView。这个文本视图填充了一个字符串。字符串可以很短也可以很长。根据字符串的长度,文本视图的高度必须进行调整。 我使用故事板和自动布局。
我对 textview 的高度有一些问题。
有时,高度会完美地适应文本。有时,不,文本在第一行被裁剪。下面,textview 是黄色的。蓝色是滚动视图内的容器视图。紫色是拍照的地方。
文本来自我的核心数据库,它们是字符串属性。
在屏幕 1 和屏幕 2 之间,唯一改变的是字符串。
如果我在控制台中打印字符串,我就会得到正确的文本:
my amazing new title
Another funny title for demo
我的 textview 的限制:
我不明白为什么我有 2 个不同的显示器。
编辑
我尝试了@Nate 的建议,在 viewDidLoad 中,我添加了:
myTextViewTitle.text="my amazing new title"
myTextViewTitle.setContentHuggingPriority(1000, forAxis: UILayoutConstraintAxis.Vertical)
myTextViewTitle.setContentCompressionResistancePriority(1000, forAxis: UILayoutConstraintAxis.Vertical)
myTextViewTitle.setTranslatesAutoresizingMaskIntoConstraints(false)
let views = ["new_view": myTextViewTitle]
var constrs = NSLayoutConstraint.constraintsWithVisualFormat("|-8-[new_view]-8-|", options: NSLayoutFormatOptions(0), metrics: nil, views: views)
self.view.addConstraints(constrs)
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-8-[new_view]", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
self.myTextViewTitle.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[new_view(220@300)]", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
没有结果。在界面生成器中为我的文本视图添加或不添加高度限制...
编辑 2
我需要一个 UITextView 而不是 UIlabel,因为有后退按钮,才能使用排除路径。
let exclusionPathBack:UIBezierPath = UIBezierPath(rect: CGRect(x:backButton.bounds.origin.x, y:backButton.bounds.origin.y, width:backButton.bounds.width+10, height:backButton.bounds.height))
myTextViewTitle.textContainer.exclusionPaths=[exclusionPathBack]
为什么不用后退按钮的图像和文本的 UILabel,并使用自动布局来定位它们?也许还有黄色背景的第三个视图。
我找到了解决办法。
我关注的是我的 UITextView 的高度,然后我读了一篇 post 谈论纵横比的文章。我想尝试一下,结果成功了!
所以在情节提要中,我为文本视图添加了纵横比,并选中了 "Remove at build time" 选项。
在viewDidLayoutSubviews()中,我写了:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let contentSize = self.myTextViewTitle.sizeThatFits(self.myTextViewTitle.bounds.size)
var frame = self.myTextViewTitle.frame
frame.size.height = contentSize.height
self.myTextViewTitle.frame = frame
aspectRatioTextViewConstraint = NSLayoutConstraint(item: self.myTextViewTitle, attribute: .Height, relatedBy: .Equal, toItem: self.myTextViewTitle, attribute: .Width, multiplier: myTextViewTitle.bounds.height/myTextViewTitle.bounds.width, constant: 1)
self.myTextViewTitle.addConstraint(aspectRatioTextViewConstraint!)
}
完美运行。
我对一个极其相似问题的简单解决方案:
我使用了行数设置为 0 的标签,而不是尝试使用文本字段或视图。然后我将前缘和后缘剪裁到标签的容器中,在我的例子中,它们限制了它们的宽度,0 作为约束的常量。要注意的是将行数设置为 0,以允许标签根据其内容增长或收缩。对于我为宽度配置的所有不同大小 类(在我的例子中是容器宽度),文本永远不会被截断并且标签的高度永远不会超过它们的内容。针对 IOS 8.0 及更高版本进行了测试(还要确保在所有标签的 'Preferred Width' 属性旁边取消选中 'explicit',以便标签宽度根据不同大小进行调整 类)- 完美运行.
首先,禁用 UITextView 的可滚动。 两个选项:
- 取消选中在 .xib 中启用滚动。
- [TextView setScrollEnabled:NO];
创建一个 UITextView 并将其与 IBOutlet (TextView) 连接。 添加默认高度的 UITextView 高度约束,将其与 IBOutlet (TextViewHeightConstraint) 连接。 当您异步设置 UITextView 的文本时,您应该计算 UITextView 的高度并将 UITextView 的高度约束设置为它。 示例代码:
CGSize sizeThatFitsTextView = [TextView sizeThatFits:CGSizeMake(TextView.frame.size.width, MAXFLOAT)];
TextViewHeightConstraint.constant = sizeThatFitsTextView.height;
在swift 2.3:
func textViewDidChange(textView: UITextView) {
let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.max))
if size.height != TXV_Height.constant && size.height > textView.frame.size.height{
TXV_Height.constant = size.height
textView.setContentOffset(CGPointZero, animated: false)
}
}
在Swift 3.0 中,其中 tvHeightConstraint 是主题 TextView 的高度约束(如果用于多个文本视图,会将其添加到函数输入中):
func textViewDidChange(textView: UITextView) {
let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
if size.height != tvHeightConstraint.constant && size.height > textView.frame.size.height{
tvHeightConstraint.constant = size.height
textView.setContentOffset(CGPoint.zero, animated: false)
}
}
H/T @cmi 和@Pablo Ruan
我已经修改了您的代码并将其用于:布局子视图和 textViewDidChange。非常感谢你让我在一个小时的故障排除后度过了愉快的一天...
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
textViewDidChange(self.recordingTitleTV)
}
func textViewDidChange(_ textView: UITextView) {
let contentSize = textView.sizeThatFits(textView.bounds.size)
var frame = textView.frame
frame.size.height = contentSize.height
textView.frame = frame
let aspectRatioTextViewConstraint = NSLayoutConstraint(item: textView, attribute: .height, relatedBy: .equal, toItem: textView, attribute: .width, multiplier: textView.bounds.height/textView.bounds.width, constant: 1)
textView.addConstraint(aspectRatioTextViewConstraint)
}