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

UITextView插入NSAttributedString后光标跳至末尾 列表编辑异常求助

问题描述

我正在基于UITextView实现支持有序列表(ol)/无序列表(ul)的富文本编辑器,当前运行情况如下:
正常光标运行效果:
正常光标运行效果
编辑器首先会将HTML内容转换为NSAttributedString,使用如下HTML内容时运行正常:

<ol>
    <li>123456</li>
    <li>123456</li>
    <li>123456</li>
    <li>123456</li>
    <li>123456</li>
</ol>
<br/>
<ul>
    <li>123456</li>
    <li>123456</li>
    <li>123456</li>
</ul>
<br/>
<ol>
    <li>abcdef</li>
    <li>abcdef</li>
    <li>abcdef</li>
</ol>

但如果在内容顶部添加普通文本,就会出现异常行为:
光标跳转异常效果:
光标跳转异常效果
可以看到,新建有序列表行后输入字符时,光标会直接跳转到内容末尾,看起来系统在尝试重置我之前创建的行的样式。
出现异常时转换所用的HTML内容如下:

Just some text on top
<ol>
    <li>123456</li>
    <li>123456</li>
    <li>123456</li>
    <li>123456</li>
    <li>123456</li>
</ol>
<br/>
<ul>
    <li>123456</li>
    <li>123456</li>
    <li>123456</li>
</ul>
<br/>
<ol>
    <li>abcdef</li>
    <li>abcdef</li>
    <li>abcdef</li>
</ol>

我发现每次新建有序列表行输入字符时,系统都会重新格式化当前有序列表的样式,导致控件的attributedText发生变化,但我不清楚该问题的来源。

原因分析

该问题是UITextView内置HTML富文本解析的固有特性:系统会将<ol>/<ul>标签转换为自带NSListStyleAttribute的段落属性,当富文本的起始位置为非列表的普通文本时,编辑列表项触发的样式重计算逻辑会触发系统全量重写整个attributedText,原有光标位置失效,最终自动跳转到文本末尾。

解决方案
  • 方案1:调整HTML结构
    转NSAttributedString前,给所有无标签包裹的顶层普通文本统一套上<p>标签,保证顶层内容都是独立块级元素,避免系统解析时把普通文本和后续列表的段落样式合并。解析时固定解析参数,减少不可控性:
    NSDictionary *options = @{
        NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
        NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)
    };
    NSAttributedString *attrStr = [[NSAttributedString alloc] initWithData:[html dataUsingEncoding:NSUTF8StringEncoding] options:options documentAttributes:nil error:nil];
    
  • 方案2:手动恢复光标位置
    实现UITextView代理方法,在系统修改文本前记录当前光标偏移量,文本变更完成后手动重置光标位置:
    - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
        NSInteger targetOffset = range.location + text.length;
        dispatch_async(dispatch_get_main_queue(), ^{
            textView.selectedRange = NSMakeRange(targetOffset, 0);
        });
        return YES;
    }
    
  • 方案3:自定义列表样式
    自行实现列表序号/圆点绘制、行首缩进逻辑,不在NSAttributedString中使用系统自带的NSListStyleAttribute属性,从根源避免系统触发列表样式重计算。
  • 方案4:统一添加前置占位元素
    不想修改现有解析逻辑的前提下,可以直接在所有HTML内容开头加一个高度为0的空<p>标签,让列表的父级结构和无顶部普通文本的场景保持一致,即可规避该问题。

内容的提问来源于stack exchange,提问作者Huy.Vu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 08:12:02