问题描述
我有一个包含 override fun onActivityResult(requestCode: Int,resultCode: Int,data: Intent?) {
super.onActivityResult(requestCode,resultCode,data)
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
val bitmap=BitmapFactory.decodeFile(currentPhotoPath)
imageView?.setimageBitmap(bitmap)
}
}
的 UITextView
。我想调整文本视图的大小,以便在给定宽度的情况下显示整个字符串而无需滚动。
NSAttributedString
有一个方法可以计算给定大小的边界矩形
NSAttributedString
但不幸的是它似乎不起作用,因为它总是返回单行的高度。
解决方法
多次尝试后,我发现我设置的 NSAttributedString
有 byTruncatingTail
作为 lineBreakMode
的 NSParagraphStyle
值(这是我们在应用程序中使用的默认值).
要实现所需的行为,我必须将其更改为 byWordWrapping
或 byCharWrapping
。
let paragraphStyle = NSMutableParagraphStyle()
// When setting "byTruncatingTail" it returns a single line height
// paragraphStyle.lineBreakMode = .byTruncatingTail
paragraphStyle.lineBreakMode = .byWordWrapping
let stringAttributes: [NSAttributedString.Key: Any] = [.font: UIFont(name: "Avenir-Book",size: 16.0)!,.paragraphStyle: paragraphStyle]
let attributedString = NSAttributedString(string: string,attributes: stringAttributes)
let computedSize = attributedString.boundingRect(with: CGSize(width: 200,height: CGFloat.greatestFiniteMagnitude),options: .usesLineFragmentOrigin,context: nil)
computedSize.height
请注意,在 byTruncatingTail
上设置具有 UILabel
值的属性字符串(其中 numberOfLines
值为 0)时,该字符串会“自动”调整为多行大小,这不会t 在计算 boundingRect
时发生。
在计算用于 NSAttributedString
内部的 UITextView
高度时,还有其他因素需要牢记(这些因素中的每一个都可能导致字符串未完全包含在文本视图中):>
1.边界改变时重新计算高度
因为高度是基于边界的,所以当边界改变时应该重新计算。这可以通过在 bounds
键路径上使用 KVO 来实现,在此更改时布局无效。
observe(\.bounds) { (_,_) in
invalidateIntrinsicContentSize()
layoutIfNeeded()
}
就我而言,我使自定义 intrinsicContentSize
的 UITextView
无效,因为这是我根据计算出的字符串高度调整它的大小的方式。
2.使用 NSTextContainer
宽度
使用 textContainer.width
(而不是 bounds.width
)作为用于 boundingRect
方法调用的固定宽度,因为它保留了任何 textContainerInset
值(尽管 {{1 }} 和 left
默认值为 0)
3.将垂直 right
值添加到字符串高度
计算 textContainerInsets
高度后,我们应该添加 NSAttributedString
和 textContainerInsets.top
以计算正确的 textContainerInsets.bottom
高度(它们的默认值为 8.0...)
UITextField
4.移除 lineFragmentPadding
将 0 设置为 override var intrinsicContentSize: CGSize {
let computedHeight = attributedText.boundingHeight(forFixedWidth: textContainer.size.width)
return CGSize(width: bounds.width,height: computedHeight + textContainerInset.top + textContainerInset.bottom)
}
的值,或者,如果您想要它,请记住在计算 lineFragmentPadding
高度之前将其值从“固定宽度”中删除
NSAttributedString
5.将 textView.textContainer.lineFragmentPadding = 0
应用于计算高度
ceil
返回的高度值可以是小数,如果我们按原样使用它可能会导致最后一行不显示。将其传递给 boundingRect
函数以获取上整数值,以避免向下舍入。
一种可能的方法是将 UITextView
子类化以在其 contentSize 确实发生变化时通知您(~文本的大小)。
class MyExpandableTextView: UITextView {
var onDidChangeContentSize: ((CGSize) -> Void)?
override var contentSize: CGSize {
didSet {
onDidChangeContentSize?(contentSize)
}
}
}
在 “父查看”:
@IBOulet var expandableTextView: MyExpandableTextView! //Do not forget to set the class in the Xib/Storyboard
// or
var expandableTextView = MyExpandableTextView()
并应用效果:
expandableTextView. onDidChangeContentSize = { [weak self] newSize in
// if you have a NSLayoutConstraint on the height:
// self?.myExpandableTextViewHeightConstraint.constant = newSize.height
// else if you play with "frames"
// self?.expandableTextView.frame.height = newSize.height
}