swift - NSTextList 格式化
问题描述
我试图弄清楚如何使用 NSTextList 但除了这个 SO question和this blog 中的评论之外,在网上几乎没有找到有用的信息。
使用这个我已经能够创建一个粗略的例子来弄清楚:
let textView = NSTextView()
//Create NSTextList
let list = NSTextList(markerFormat: .decimal, options: 0)
list.startingItemNumber = 1
//Create NSParagraphStyle with text list
let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
paragraphStyle.textLists = [list]
let attributes = [NSAttributedString.Key.paragraphStyle : paragraphStyle]
//Add attributes to list block
let nsmutableAttributedString = NSMutableAttributedString(string: "\t\(list.marker(forItemNumber: 1))\tList Item 1 ", attributes: attributes)
textView.textStorage?.setAttributedString(nsmutableAttributedString)
return textView
这很好用,当应用程序运行时,按下enter
会创建一个格式正确的新行,按下会正确tab
缩进列表项。
一切都很好......但是,标记周围的间距似乎不正确,并且不能反映您在 TextEdit 中得到的内容。
这是我的 textView,请注意标记周围较大的间距,在下面突出显示的过程之后,它会恢复为“默认”文本编辑间距...
我希望摆脱这三件事:
- 我做错了吗?我很确定我必须
\t
在标记周围使用才能使其工作。 - 关于如何实现苹果在其所有文本编辑应用程序(笔记、文本编辑等)中实现的标记周围默认间距的任何想法
- NSTextList 的任何一般提示。那里没有太多东西,所以如果有人能分享他们的知识,将不胜感激。
解决方案
注意事项:我也对此感到困惑,这是我尝试实施您上面链接的评论中的信息。
在我正在从事的项目中,我面临着类似的问题。发现 textView 正在更改 tabStops 数组 ( paragraphStyle.tabStops
) 从默认值,当用户从嵌套列表移回主列表时,正如您在屏幕截图中所展示的那样。要进行验证,请尝试打印以控制第一个 tabStop ( paragraphStyle.tabStops.first.location
) 的位置,用于保存“列表项 1”的段落与保存“列表继续”的段落。
我提出并仍在迭代的天真的解决方案是检查编辑的段落是否具有:
- 一个文本列表
- 一个 tabStop,其位置位于默认最左侧的 tabStop 位置的左侧。
如果上面的两个条件检查出来,我将已编辑段落的 tabStops 重置为默认值。
我目前正在研究以下功能的变体,专门用于解决您概述的问题。我调用了 didProcessEditing NSTextStorage 委托方法中的函数,传入了 textStorage 和editedRange。
func handleTabStopsIssue(textStorage: NSTextStorage, editedRange: NSRange) {
//Determine range of the edited paragraph (this is encompases the editedRange).
let rangeOfEditedParagraph = textStorage.mutableString.paragraphRange(for: editedRange)
//Retrieve the edited paragraph as attributed string
let editedParagraph = textStorage.attributedSubstring(from: rangeOfEditedParagraph)
//Enumerate the paragraphStyle attribute in the inputted paragraph NSAttributedString
editedParagraph.enumerateAttribute(.paragraphStyle, in: NSRange(location: 0, length: editedParagraph.length), options: .longestEffectiveRangeNotRequired, using: {atts, subrange, _ in
//Determine whether or not paragraph contains a textList
guard let parStyle = atts as? NSParagraphStyle else { return }
let parHasTextList = !parStyle.textLists.isEmpty
//Retrieve the default tabStops to compare their location with inputted paragraph tabStop locations
let defaultTabStops = NSParagraphStyle.default.tabStops
guard let firstDefaultTabStop = defaultTabStops.first else { return }
guard let inputParFirstTabStop = parStyle.tabStops.first else { return }
print("firstDefaultTabStop \(firstDefaultTabStop) of location \(firstDefaultTabStop.location)")
print("currentParTabStop \(inputParFirstTabStop) of location \(inputParFirstTabStop.location)")
//If parStyle has textList, and its first tab stop is located to the left of the default tab stops...
if (inputParFirstTabStop.location < firstDefaultTabStop.location) && parHasTextList {
print(" Resetting tabstops!")
//Set the inputted paragraph's tab stops, to default
let newParStyle = parStyle.mutableCopy() as! NSMutableParagraphStyle
newParStyle.tabStops = defaultTabStops
textView.textStorage?.addAttribute(.paragraphStyle, value: newParStyle, range: rangeOfEditedParagraph)
}
})
}
我在这里向 gitHub 上传了一个工作演示:https ://github.com/MQumairi/TextKit-List/blob/main/List%20Problems/ViewController.swift
将清晰度优先于效率,代码可能会更有效率。只是想展示我的逻辑。
这仍在进行中,因为上述方法不适用于阿拉伯语等从右到左的语言。需要处理那个边缘情况。但这是一个起点,希望可以帮助其他人解决这个问题。
推荐阅读
- android - 如何使用 API 谷歌地图 SDK Nativeproject
- java - 如何在 JNI 中将 jstring 转换为 std::string
- javascript - 为什么我的图像在水平滚动中被剪裁 ij 分辨率较低
- angular - Angular Validator 模式未按预期工作
- powershell - 使用 Powershell 从文本文件中删除第一个字符
- javascript - 将动态变量传递给数组
- c# - 来自控制台应用程序的 Microsoft Word COM 互操作
- c# - 如何在强类型类中转换从 LUISRuntimeClient 返回的 Prediction.Entities
- python - 加入单独的箱线图图形文件
- c# - 单元测试中的 Azure.Core.ResponseHeaders