IntrinsicContentSize在iOS15生效但iOS13/14不生效的适配问题
iOS13/14下UITextView自适应高度兼容方案
修复后代码
final private class UIKitTextView: UITextView { override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) commonInit() } required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } private func commonInit() { // 自动计算intrinsicContentSize必须关闭滚动 isScrollEnabled = false // 可选:移除默认文本边距,根据业务需求调整 textContainer.lineFragmentPadding = 0 } override var contentSize: CGSize { didSet { guard oldValue != contentSize else { return } invalidateIntrinsicContentSize() // iOS13/14兼容:主动触发布局更新,强制系统查询新的尺寸 setNeedsLayout() layoutIfNeeded() superview?.setNeedsLayout() } } override public var intrinsicContentSize: CGSize { var calculatedSize = super.intrinsicContentSize // 按当前宽度适配高度,避免宽度异常 if bounds.width > 0 { calculatedSize = sizeThatFits(CGSize(width: bounds.width, height: .greatestFiniteMagnitude)) } print("Invalidate size: \(calculatedSize)") return calculatedSize } }
关键修复说明
- 必须明确设置
isScrollEnabled = false,这是UITextView自动计算intrinsicContentSize的必要条件,iOS15对该配置的容错性更高,iOS13/14未显式关闭滚动时不会主动触发尺寸更新 - 调用
invalidateIntrinsicContentSize后新增setNeedsLayout()、layoutIfNeeded()调用,强制当前视图立即刷新布局,同时触发父视图布局失效,让系统必须查询最新的intrinsicContentSize值 - 优化intrinsicContentSize计算逻辑,使用系统原生
sizeThatFits方法计算尺寸,避免直接取contentSize带来的textContainer边距计算偏差,适配不同系统版本的文本布局规则 - 新增
oldValue != contentSize判断,过滤重复的尺寸变化通知,减少无意义的布局刷新开销
额外排查注意事项
- 检查UITextView的Auto Layout约束是否正确,只需设置位置类约束(如leading、top、trailing),不要添加固定高度约束
- 如果有最大行数限制,可在获取
calculatedSize后,结合font.lineHeight和最大行数裁剪高度,避免超出显示限制
内容的提问来源于stack exchange,提问作者qwerty123
相关产品推荐
相关产品推荐

