You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UITextView如何禁用滚动同时保留多行功能?

解决UITextView禁用滚动但保留多行输入的问题

这个坑我之前踩过好几次!很多人刚上手UITextView都会遇到:设置textView.isScrollEnabled = false后,本以为只是禁用滚动,结果连多行输入/显示的能力也没了。其实核心原因是关闭滚动后,UITextView会失去自动调整自身高度来适配内容的逻辑,超出默认高度的内容就被截断了。下面给你几个靠谱的解决方案:

方法一:通过代理动态调整高度(最常用)

这个方法适合快速实现,不需要子类化,只需要利用UITextView的代理方法实时计算内容高度,更新对应的约束或frame。

步骤:

  1. 先把isScrollEnabled设为false,并设置代理
  2. 给UITextView添加一个高度约束的引用(用AutoLayout的话)
  3. 在textViewDidChange代理方法里计算内容高度,更新约束

Swift代码示例:

// 先在ViewController里定义高度约束的引用
@IBOutlet weak var textViewHeightConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()
    // 基础设置
    textView.isScrollEnabled = false
    textView.delegate = self
    // 初始化时计算一次高度,避免初始显示异常
    updateTextViewHeight()
}

// 封装更新高度的方法
private func updateTextViewHeight() {
    let fixedWidth = textView.frame.size.width
    // 计算适配内容的最小高度
    let contentSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
    textViewHeightConstraint.constant = contentSize.height
}

// 实现UITextView代理
extension ViewController: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        updateTextViewHeight()
    }
}

小提示:

  • 如果不用AutoLayout,直接修改textView.frame.size.height也可以,但AutoLayout是更推荐的方式
  • 记得初始化时调用一次高度更新,不然刚加载的文本可能显示不全

方法二:子类化UITextView重写intrinsicContentSize(更优雅)

如果你的项目里多个地方需要这个功能,子类化是更简洁的方案,复用性强。通过重写intrinsicContentSize,让UITextView自己计算合适的高度,不需要手动维护约束。

Swift代码示例:

class AutoHeightTextView: UITextView {
    override var intrinsicContentSize: CGSize {
        // 计算适配内容的高度
        let contentSize = self.sizeThatFits(CGSize(width: self.frame.width, height: CGFloat.greatestFiniteMagnitude))
        // 返回宽度自适应,高度为内容高度
        return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        // 当布局变化时,重新计算intrinsicContentSize
        if bounds.size != intrinsicContentSize {
            invalidateIntrinsicContentSize()
        }
    }
}

使用方式:

  1. 在Storyboard里把UITextView的Class改成AutoHeightTextView
  2. 设置isScrollEnabled = false
  3. 给TextView添加左右上下的约束(不要加固定高度约束)
  4. 运行后它会自动根据内容调整高度,支持多行输入且不会滚动

方法三:Objective-C版本实现

如果你的项目用的是Objective-C,对应的实现如下:

动态调整高度的代码:

// 定义高度约束的引用
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewHeightConstraint;

- (void)viewDidLoad {
    [super viewDidLoad];
    self.textView.scrollEnabled = NO;
    self.textView.delegate = self;
    // 初始化更新高度
    [self updateTextViewHeight];
}

- (void)updateTextViewHeight {
    CGSize fixedSize = CGSizeMake(self.textView.frame.size.width, CGFLOAT_MAX);
    CGSize contentSize = [self.textView sizeThatFits:fixedSize];
    self.textViewHeightConstraint.constant = contentSize.height;
}

#pragma mark - UITextViewDelegate
- (void)textViewDidChange:(UITextView *)textView {
    [self updateTextViewHeight];
}

子类化的Objective-C代码:

@interface AutoHeightTextView : UITextView
@end

@implementation AutoHeightTextView

- (CGSize)intrinsicContentSize {
    CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)];
    return CGSizeMake(UIViewNoIntrinsicMetric, contentSize.height);
}

- (void)layoutSubviews {
    [super layoutSubviews];
    if (!CGSizeEqualToSize(self.bounds.size, self.intrinsicContentSize)) {
        [self invalidateIntrinsicContentSize];
    }
}

@end

额外注意事项

  • 如果你的UITextView有placeholder,记得同步调整placeholder的高度,避免遮挡
  • 可以调整textContainerInset和contentInset来优化内容的边距,避免内容紧贴边缘
  • 不要同时设置isScrollEnabled = false和固定高度约束,否则动态调整会失效

内容的提问来源于stack exchange,提问作者Md. Mostafizur Rahman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:57:09