如何使用Text Kit 2 API在UITextView中实现嵌套编号列表?
实现Text Kit 2嵌套编号列表的正确方式
可以通过UIKit的Text Kit 2实现类似苹果笔记的嵌套编号列表,核心是使用**NSTextListElement**(Text Kit 2专属的列表元素模型)来构建层级化结构,而非依赖旧的NSTextList与NSParagraphStyle的组合——后者在嵌套场景下无法正确处理缩进与层级关联。
核心原理
Text Kit 2通过NSTextContentStorage管理内容,内容由NSTextElement(段落、列表等)组成。嵌套列表需要将NSTextListElement作为父容器,内部嵌套子NSTextListElement或NSTextParagraphElement,以此明确层级关系,系统会自动处理编号和缩进。
完整实现代码
替换原代码中的loadText方法,并调整内容初始化逻辑:
class ViewController: UIViewController { var textView: UITextView! override func viewDidLoad() { super.viewDidLoad() textView = UITextView(usingTextLayoutManager: true) textView.alwaysBounceVertical = true textView.keyboardDismissMode = .interactive textView.layer.borderColor = UIColor.black.cgColor textView.layer.borderWidth = 2 view.addSubview(textView) textView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), textView.leadingAnchor.constraint(equalTo: view.leadingAnchor), textView.trailingAnchor.constraint(equalTo: view.trailingAnchor), textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) loadNestedList() } func loadNestedList() { // 1. 创建最外层编号列表(十进制数字) let outerList = NSTextListElement(markerFormat: .decimal, startingItemNumber: 1) // 外层列表项1 let outerItem1 = NSTextParagraphElement(content: NSAttributedString(string: "外层列表项1")) outerList.addElement(outerItem1) // 2. 创建内层嵌套列表(小写字母) let innerList = NSTextListElement(markerFormat: .lowercaseLetter, startingItemNumber: 1) // 内层列表项 let innerItem1 = NSTextParagraphElement(content: NSAttributedString(string: "内层列表项1")) let innerItem2 = NSTextParagraphElement(content: NSAttributedString(string: "内层列表项2")) innerList.addElement(innerItem1) innerList.addElement(innerItem2) // 将内层列表作为外层列表的子项添加 outerList.addElement(innerList) // 外层列表项2 let outerItem2 = NSTextParagraphElement(content: NSAttributedString(string: "外层列表项2")) outerList.addElement(outerItem2) // 3. 将根列表添加到Text Content Storage textView.textLayoutManager.textContentStorage.addElement(outerList) } }
关键说明
NSTextListElement初始化:通过markerFormat指定编号样式(十进制、字母、罗马数字等),startingItemNumber设置起始编号。- 层级嵌套:直接调用
addElement(_:)将子列表或段落元素添加到父列表中,系统会自动根据层级计算缩进和编号序列。 - 替代旧方式:不再需要手动设置
firstLineHeadIndent或headIndent,Text Kit 2会基于列表层级自动处理排版。
原代码问题解析
你之前使用NSTextList+NSParagraphStyle的方式属于Text Kit 1的实现逻辑,Text Kit 2虽然兼容基础样式,但嵌套场景下无法识别层级关系,导致缩进不生效。改用NSTextListElement的元素层级模型,才能让系统正确处理嵌套列表的排版和编号。
内容的提问来源于stack exchange,提问作者FE_Tech
相关产品推荐
相关产品推荐

