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

UIScrollView中激活的UITextView自动滚动异常问题咨询

问题分析与解决方案

这是标准行为吗?

不是,这属于UITextView在处理宽于屏幕尺寸的非滚动文本视图时的适配逻辑bug。系统默认会尝试让UITextView的可视区域适配屏幕,但错误地将TextView的右边缘作为滚动目标,而非当前光标位置。

如何禁用自动滚动并让自定义逻辑生效?

核心思路是先阻断UITextView内部的自动滚动触发,再通过代理方法实现自定义的光标位置滚动。

1. 重写UITextView的scrollRangeToVisible:方法

系统内部会调用这个方法来触发TextView的自动滚动,重写为空实现即可完全阻断默认行为:

Objective-C 实现

@interface CustomTextView : UITextView
@end

@implementation CustomTextView

- (void)scrollRangeToVisible:(NSRange)range {
    // 空实现,禁止UITextView内部自动滚动
}

@end

Swift 实现

class CustomTextView: UITextView {
    override func scrollRangeToVisible(_ range: NSRange) {
        // 空实现,禁用默认滚动逻辑
    }
}

2. 实现自定义光标滚动逻辑

在UITextViewDelegate的textViewDidChangeSelection:方法中,获取光标对应的矩形区域,转换到外层UIScrollView的坐标系后,调用scrollRectToVisible:实现精准滚动:

Objective-C 实现

- (void)textViewDidChangeSelection:(UITextView *)textView {
    if (!textView.selectedTextRange) return;
    
    // 获取光标所在的矩形
    CGRect caretRect = [textView firstRectForRange:textView.selectedTextRange];
    // 转换坐标到外层UIScrollView
    CGRect scrollViewRect = [textView convertRect:caretRect toView:self.mainScrollView];
    // 添加内边距,避免光标贴边显示
    UIEdgeInsets visibleInsets = UIEdgeInsetsMake(20, 20, 20, 20);
    scrollViewRect = UIEdgeInsetsInsetRect(scrollViewRect, visibleInsets);
    
    [self.mainScrollView scrollRectToVisible:scrollViewRect animated:YES];
}

Swift 实现

func textViewDidChangeSelection(_ textView: UITextView) {
    guard let selectedRange = textView.selectedTextRange else { return }
    
    var caretRect = textView.firstRect(for: selectedRange)
    // 转换坐标到外层UIScrollView
    let scrollViewRect = textView.convert(caretRect, to: mainScrollView)
    // 添加内边距优化显示效果
    let visibleInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
    let adjustedRect = scrollViewRect.inset(by: visibleInsets)
    
    mainScrollView.scrollRectToVisible(adjustedRect, animated: true)
}

3. 额外优化点

  • 确保你的CustomTextView的isScrollEnabled属性设置为NO(Objective-C)或false(Swift),避免系统残留的滚动逻辑干扰;
  • 在textViewDidBeginEditing:方法中也执行一次上述滚动逻辑,确保TextView成为第一响应者时,光标能立即处于可视区域。

内容的提问来源于stack exchange,提问作者Paul

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 03:43:34