SwiftyMarkdown 使用合理的默认设置和 Swift 风格的语法,将 Markdown 文件和字符串转换为 NSAttributedString
。 它使用动态类型来正确设置字体大小,无论您想使用什么字体。
SwiftyMarkdown 现在具有更强大、更可靠的基于规则的行处理和字符标记引擎。 它增加了对存储在捆绑包中的图像(
)、代码块、块引用和无序列表的支持!
行级属性现在可以应用段落对齐方式(例如,h2.aligment = .center
),并且可以通过将 underlineLinks
设置为 true
来选择性地对链接进行下划线。
它还使用系统颜色 .label
作为 iOS 13 及更高版本上的默认字体颜色,以便开箱即用地支持暗黑模式。
已启用对所有 Apple 平台的支持。
pod 'SwiftyMarkdown'
在 Xcode 中,File -> Swift Packages -> Add Package Dependency
并添加 GitHub URL。
从文本字符串读取 Markdown...
let md = SwiftyMarkdown(string: "# Heading\nMy *Markdown* string")
md.attributedString()
...或从 URL 读取。
if let url = Bundle.main.url(forResource: "file", withExtension: "md"), md = SwiftyMarkdown(url: url ) {
md.attributedString()
}
如果要在 SwiftyMarkdown 初始化后使用不同的字符串,现在可以这样做
let md = SwiftyMarkdown(string: "# Heading\nMy *Markdown* string")
md.attributedString(from: "A **SECOND** Markdown string. *Fancy!*")
然后,可以将带属性的字符串分配给任何支持带属性文本的标签或文本控件。
let md = SwiftyMarkdown(string: "# Heading\nMy *Markdown* string")
let label = UILabel()
label.attributedText = md.attributedString()
*italics* or _italics_
**bold** or __bold__
~~Linethrough~~Strikethroughs.
`code`
# Header 1
or
Header 1
====
## Header 2
or
Header 2
---
### Header 3
#### Header 4
##### Header 5 #####
###### Header 6 ######
Indented code blocks (spaces or tabs)
[Links](http://voyagetravelapps.com/)

[Referenced Links][1]
![Referenced Images][2]
[1]: http://voyagetravelapps.com/
[2]: <Name of asset in bundle>
> Blockquotes
- Bulleted
- Lists
- Including indented lists
- Up to three levels
- Neat!
1. Ordered
1. Lists
1. Including indented lists
- Up to three levels
复合规则也有效,例如
It recognises **[Bold Links](http://voyagetravelapps.com/)**
Or [**Bold Links**](http://voyagetravelapps.com/)
图像将作为 NSTextAttachment
插入到返回的 NSAttributedString
中(遗憾的是,这在 watchOS 上不起作用,因为 NSTextAttachment
不可用)。
使用直接的点语法设置每个段落和字符样式类型的属性
md.body.fontName = "AvenirNextCondensed-Medium"
md.h1.color = UIColor.redColor()
md.h1.fontName = "AvenirNextCondensed-Bold"
md.h1.fontSize = 16
md.h1.alignmnent = .center
md.italic.color = UIColor.blueColor()
md.underlineLinks = true
md.bullet = "🍏"
在 iOS 上,指定的字体大小将根据用户的动态类型设置进行调整。
存储库中包含一个示例项目。 打开 Example/SwiftyMarkdown.xcodeproj
文件以开始使用。
SwiftyMarkdown 识别 YAML 前置元数据,并将使用它找到的键值对填充 frontMatterAttributes
属性。
h1.fontName : String
h1.fontSize : CGFloat
h1.color : UI/NSColor
h1.fontStyle : FontStyle
h1.alignment : NSTextAlignment
h2.fontName : String
h2.fontSize : CGFloat
h2.color : UI/NSColor
h2.fontStyle : FontStyle
h2.alignment : NSTextAlignment
h3.fontName : String
h3.fontSize : CGFloat
h3.color : UI/NSColor
h3.fontStyle : FontStyle
h3.alignment : NSTextAlignment
h4.fontName : String
h4.fontSize : CGFloat
h4.color : UI/NSColor
h4.fontStyle : FontStyle
h4.alignment : NSTextAlignment
h5.fontName : String
h5.fontSize : CGFloat
h5.color : UI/NSColor
h5.fontStyle : FontStyle
h5.alignment : NSTextAlignment
h6.fontName : String
h6.fontSize : CGFloat
h6.color : UI/NSColor
h6.fontStyle : FontStyle
h6.alignment : NSTextAlignment
body.fontName : String
body.fontSize : CGFloat
body.color : UI/NSColor
body.fontStyle : FontStyle
body.alignment : NSTextAlignment
blockquotes.fontName : String
blockquotes.fontSize : CGFloat
blockquotes.color : UI/NSColor
blockquotes.fontStyle : FontStyle
blockquotes.alignment : NSTextAlignment
link.fontName : String
link.fontSize : CGFloat
link.color : UI/NSColor
link.fontStyle : FontStyle
bold.fontName : String
bold.fontSize : CGFloat
bold.color : UI/NSColor
bold.fontStyle : FontStyle
italic.fontName : String
italic.fontSize : CGFloat
italic.color : UI/NSColor
italic.fontStyle : FontStyle
code.fontName : String
code.fontSize : CGFloat
code.color : UI/NSColor
code.fontStyle : FontStyle
strikethrough.fontName : String
strikethrough.fontSize : CGFloat
strikethrough.color : UI/NSColor
strikethrough.fontStyle : FontStyle
underlineLinks : Bool
bullet : String
FontStyle
是一个枚举,包含以下情况:normal
、bold
、italic
和 bolditalic
,让您可以更精确地控制行和字符样式的外观。 例如,您可能希望块引用默认具有斜体样式
md.blockquotes.fontStyle = .italic
或者,如果您喜欢一点混乱
md.bold.fontStyle = .italic
md.italic.fontStyle = .bold
SwiftyMarkdown 使用基于规则的行处理和自定义引擎,该引擎不再仅限于 Markdown。 规则按顺序从上到下处理。 首先进行行处理,然后根据字符规则应用字符样式。
例如,以下是如何在 SwiftyMarkdown 中设置一小部分 Markdown 行标签
enum MarkdownLineStyle : LineStyling {
case h1
case h2
case previousH1
case codeblock
case body
var shouldTokeniseLine: Bool {
switch self {
case .codeblock:
return false
default:
return true
}
}
func styleIfFoundStyleAffectsPreviousLine() -> LineStyling? {
switch self {
case .previousH1:
return MarkdownLineStyle.h1
default :
return nil
}
}
}
static public var lineRules = [
LineRule(token: " ",type : MarkdownLineStyle.codeblock, removeFrom: .leading),
LineRule(token: "=",type : MarkdownLineStyle.previousH1, removeFrom: .entireLine, changeAppliesTo: .previous),
LineRule(token: "## ",type : MarkdownLineStyle.h2, removeFrom: .both),
LineRule(token: "# ",type : MarkdownLineStyle.h1, removeFrom: .both)
]
let lineProcessor = SwiftyLineProcessor(rules: SwiftyMarkdown.lineRules, default: MarkdownLineStyle.body)
同样,字符样式都遵循规则
enum CharacterStyle : CharacterStyling {
case link, bold, italic, code
}
static public var characterRules = [
CharacterRule(primaryTag: CharacterRuleTag(tag: "[", type: .open), otherTags: [
CharacterRuleTag(tag: "]", type: .close),
CharacterRuleTag(tag: "[", type: .metadataOpen),
CharacterRuleTag(tag: "]", type: .metadataClose)
], styles: [1 : CharacterStyle.link], metadataLookup: true, definesBoundary: true),
CharacterRule(primaryTag: CharacterRuleTag(tag: "`", type: .repeating), otherTags: [], styles: [1 : CharacterStyle.code], shouldCancelRemainingTags: true, balancedTags: true),
CharacterRule(primaryTag: CharacterRuleTag(tag: "*", type: .repeating), otherTags: [], styles: [1 : CharacterStyle.italic, 2 : CharacterStyle.bold], minTags:1 , maxTags:2),
CharacterRule(primaryTag: CharacterRuleTag(tag: "_", type: .repeating), otherTags: [], styles: [1 : CharacterStyle.italic, 2 : CharacterStyle.bold], minTags:1 , maxTags:2)
]
这些字符规则由 SwiftyMarkdown 定义
public struct CharacterRule : CustomStringConvertible {
public let primaryTag : CharacterRuleTag
public let tags : [CharacterRuleTag]
public let escapeCharacters : [Character]
public let styles : [Int : CharacterStyling]
public let minTags : Int
public let maxTags : Int
public var metadataLookup : Bool = false
public var definesBoundary = false
public var shouldCancelRemainingRules = false
public var balancedTags = false
}
primaryTag
:每个规则必须至少有一个标签,它可以是 repeating
、open
、close
、metadataOpen
或 metadataClose
之一。 repeating
标签是具有相同打开和关闭字符的标签(并且通常具有多个样式,具体取决于组中有多少个)。 例如,Markdown 中使用的 *
标签。tags
:规则可以查找的其他标签的数组。 例如,您可以在这里放置自定义规则的 close
标签。escapeCharacters
:出现在任何标签字符之前的字符,告诉扫描仪忽略该标签。styles
:应应用于打开和关闭标签之间的每个字符的样式。minTags
:要被认为是成功匹配的重复字符的最小数量。 例如,将 primaryTag
设置为 *
,将 minTag
设置为 2 意味着 **foo**
将是成功的匹配,而 *bar*
将不会。maxTags
:要被认为是成功匹配的重复字符的最大数量。metadataLookup
:用于 Markdown 引用链接。 告诉扫描仪尝试从此字典而不是从内联结果中查找元数据。definesBoundary
:为了使打开和关闭标签成功,字符串中给定位置的 boundaryCount
需要相同。 将此属性设置为 true
意味着此规则将增加其打开和关闭标签之间每个字符的 boundaryCount
。 例如,[
规则定义了一个边界。 应用它之后,字符串 *foo[bar*]
变为 *foobar*
,边界计数为 00001111
。 应用 *
规则导致输出 *foobar*
,因为打开的 *
标签和关闭的 *
标签现在具有不同的 boundaryCount
值。 它基本上是一种修复 Markdown 中 **[should not be bold**](url)
问题的方法。shouldCancelRemainingTags
:成功匹配将标记打开和关闭标签之间的每个字符已完成,从而阻止任何其他规则应用于这些字符。balancedTags
:此标志要求打开和关闭标签的长度完全相等。 例如,如果设置为 true,则 **foo*
将导致 **foo*
。 如果为 false,则输出将为 *foo
。如果您只想支持一小部分 Markdown,现在很容易做到。
此示例仅处理带有 *
和 _
字符的字符串,忽略链接、图像、代码和所有行级属性(标题、块引用等)。
SwiftyMarkdown.lineRules = []
SwiftyMarkdown.characterRules = [
CharacterRule(primaryTag: CharacterRuleTag(tag: "*", type: .repeating), otherTags: [], styles: [1 : CharacterStyle.italic, 2 : CharacterStyle.bold], minTags:1 , maxTags:2),
CharacterRule(primaryTag: CharacterRuleTag(tag: "_", type: .repeating), otherTags: [], styles: [1 : CharacterStyle.italic, 2 : CharacterStyle.bold], minTags:1 , maxTags:2)
]
如果您想创建一个规则,将 Elf
样式应用于 "The elf will speak now: %Here is my elf speaking%" 之间的一系列字符,您可以像这样设置:
enum Characters : CharacterStyling {
case elf
func isEqualTo( _ other : CharacterStyling) -> Bool {
if let other = other as? Characters else {
return false
}
return other == self
}
}
let characterRules = [
CharacterRule(primaryTag: CharacterRuleTag(tag: "%", type: .repeating), otherTags: [], styles: [1 : CharacterStyle.elf])
]
let processor = SwiftyTokeniser( with : characterRules )
let string = "The elf will speak now: %Here is my elf speaking%"
let tokens = processor.process(string)
输出是一个标记数组,等价于
[
Token(type: .string, inputString: "The elf will speak now: ", characterStyles: []),
Token(type: .repeatingTag, inputString: "%", characterStyles: []),
Token(type: .string, inputString: "Here is my elf speaking", characterStyles: [.elf]),
Token(type: .repeatingTag, inputString: "%", characterStyles: [])
]
您知道 SKLabelNode
支持带属性的文本吗? 我不知道。
let smd = SwiftyMarkdown(string: "My Character's **Dialogue**")
let label = SKLabelNode()
label.preferredMaxLayoutWidth = 500
label.numberOfLines = 0
label.attributedText = smd.attributedString()