在 SwiftUI 中将部分文本加粗

Posted

技术标签:

【中文标题】在 SwiftUI 中将部分文本加粗【英文标题】:Making parts of text bold in SwiftUI 【发布时间】:2020-05-08 03:03:26 【问题描述】:

我想知道如何在 SwiftUI 中仅将文本的部分加粗,而将其余部分保持“常规”。

我目前有:

Text("Coronavirus Disease of 2019")

我希望它打印出 COronaVirus Disease of 2019 and have'只能将某些部分加粗。

【问题讨论】:

【参考方案1】:

斯威夫特 5.5

Foundation 支持 Markdown。


在要加粗的字符周围添加双星号 (**)。

Text("**CO**rona**V**irus **D**isease of 20**19**")

在要斜体的字符周围添加下划线。

Text("Is this text _emphasized_?")

【讨论】:

实际上,**Bold**__Bold__ 都会产生粗体(而 *Italic*_Italic_ 会呈现斜体) 应该补充一点,如果字符串由于大小而被分成几部分 ex: Text("Hello there " + "world") 文本将被渲染而没有粗体【参考方案2】:

如果你不需要在这里翻译它是可能的快速变体

Text("CO").bold() + Text("rona") + Text("VI").bold() + 
    Text("rus Disease of 20") + Text("19").bold()

替代方法是将 NSAttributedString 与 UIViewRepresentableUILabel 一起使用。

【讨论】:

【参考方案3】:

添加到 Asperi 的出色答案的快速说明,如果您需要对文本应用框架或填充修饰符,则需要先对文本进行分组,然后将修饰符添加到组中。

Group  Text("CO").bold() + Text("rona") + Text("VI").bold() + Text("rus Disease of 20") + Text("19").bold() .frame(width: 100, height: 100).padding(.horizontal)

【讨论】:

【参考方案4】:

这个问题出现了很多,对于一个没有 Objective-C 背景的 Swift 新手来说,解决方案是不情愿的。上面的几个答案都很好,但总结一下问题的最佳解决方案,

Group 
    Text("CO").bold() +
    Text("rona") +
    Text("V").bold() +
    Text("irus ") +
    Text("D").bold() +
    Text("isease of 20") +
    Text("19").bold()

.font(.caption)
.frame(width: 300)

Group 是我的秘诀)

【讨论】:

【参考方案5】:

Swift 5、ios 13

这篇文章是关于改变字符文本的颜色,但你同样可以应用它使用 [a bit mask] 的技术来使某些字符加粗、闪烁、动画等等?

https://medium.com/@marklucking/an-interesting-challenge-with-swiftui-9ebb26e77376

你需要关注的两个核心部分是..

ForEach((0 ..< letter.count), id: \.self)  column in
          Text(letter[column])
            .foregroundColor(colorCode(gate: Int(self.gate), no: column) ? Color.black: Color.red)
            .font(Fonts.futuraCondensedMedium(size: fontSize))

        

还有这个用来掩盖文字的……

func colorCode(gate:Int, no:Int) -> Bool 

  let bgr = String(gate, radix:2).pad(with: "0", toLength: 16)
  let bcr = String(no, radix:2).pad(with: "0", toLength: 16)
  let binaryColumn = 1 << no - 1

  let value = UInt64(gate) & UInt64(binaryColumn)
  let vr = String(value, radix:2).pad(with: "0", toLength: 16)

  print("bg ",bgr," bc ",bcr,vr)
  return value > 0 ? true:false

【讨论】:

【参考方案6】:

@mahan 提出的解决方案很棒,但它有一个限制,即它在 iOS 15 上运行良好,但在 iOS 14 上却不行。

所以我认为对于那些需要支持 iOS 14 的人来说这是一个更好的解决方案,该解决方案是从这个网站复制的: https://www.avanderlee.com/swiftui/text-weight-combinations/

最终代码如下所示:

    @main
struct RichTextApp: App 
    var body: some Scene 
        WindowGroup 
            RichText("SwiftLee - A *weekly blog* about Swift, iOS and Xcode *Tips and Tricks*")
                .padding()
                .multilineTextAlignment(.center)
        
    

(您可以自定义字体并在文本中添加变量,例如:)

RichText(" ... *\(viewModel.title)* ...")

代码是:

import SwiftUI

struct RichText: View 

    struct Element: Identifiable 
        let id = UUID()
        let content: String
        let isBold: Bool

        init(content: String, isBold: Bool) 
            var content = content.trimmingCharacters(in: .whitespacesAndNewlines)

            if isBold 
                content = content.replacingOccurrences(of: "*", with: "")
            

            self.content = content
            self.isBold = isBold
        
    

    let elements: [Element]

    init(_ content: String) 
        elements = content.parseRichTextElements()
    

    var body: some View 
        var content = text(for: elements.first!)
        elements.dropFirst().forEach  (element) in
            content = content + self.text(for: element)
        
        return content
    
    
    private func text(for element: Element) -> Text 
        let postfix = shouldAddSpace(for: element) ? " " : ""
        if element.isBold 
            return Text(element.content + postfix)
                .fontWeight(.bold)
         else 
            return Text(element.content + postfix)
        
    

    private func shouldAddSpace(for element: Element) -> Bool 
        return element.id != elements.last?.id
    
    




extension String 

    /// Parses the input text and returns a collection of rich text elements.
    /// Currently supports asterisks only. E.g. "Save *everything* that *inspires* your ideas".
    ///
    /// - Returns: A collection of rich text elements.
    func parseRichTextElements() -> [RichText.Element] 
        let regex = try! NSRegularExpression(pattern: "\\*1(.*?)\\*1")
        let range = NSRange(location: 0, length: count)

        /// Find all the ranges that match the regex *CONTENT*.
        let matches: [NSTextCheckingResult] = regex.matches(in: self, options: [], range: range)
        let matchingRanges = matches.compactMap  Range<Int>($0.range) 

        var elements: [RichText.Element] = []

        // Add the first range which might be the complete content if no match was found.
        // This is the range up until the lowerbound of the first match.
        let firstRange = 0..<(matchingRanges.count == 0 ? count : matchingRanges[0].lowerBound)

        self[firstRange].components(separatedBy: " ").forEach  (word) in
            guard !word.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else  return 
            elements.append(RichText.Element(content: String(word), isBold: false))
        

        // Create elements for the remaining words and ranges.
        for (index, matchingRange) in matchingRanges.enumerated() 
            let isLast = matchingRange == matchingRanges.last

            // Add an element for the matching range which should be bold.
            let matchContent = self[matchingRange]
            elements.append(RichText.Element(content: matchContent, isBold: true))

            // Add an element for the text in-between the current match and the next match.
            let endLocation = isLast ? count : matchingRanges[index + 1].lowerBound
            let range = matchingRange.upperBound..<endLocation
            self[range].components(separatedBy: " ").forEach  (word) in
                guard !word.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else  return 
                elements.append(RichText.Element(content: String(word), isBold: false))
            
        

        return elements
    

    /// - Returns: A string subscript based on the given range.
    subscript(range: Range<Int>) -> String 
        let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
        let endIndex = index(self.startIndex, offsetBy: range.upperBound)
        return String(self[startIndex..<endIndex])
    

【讨论】:

这很好,但似乎从文本中删除了新行? @dqualias \n 不适合你?示例“(标题) \n(内容)” 如果我有一个像 "title \n content" 这样的字符串,那么就可以删除换行符。我认为正则表达式正在删除换行符?

以上是关于在 SwiftUI 中将部分文本加粗的主要内容,如果未能解决你的问题,请参考以下文章

在 ScrollView 中将文本对齐为前导 - SWIFTUI

如何在 SwiftUI 中将文本推送到边缘

如何在 SwiftUI 中将滚动视图添加到屏幕的特定部分? [复制]

在 SwiftUI 中,如何将primaryAction ToolbarItem 加粗?

SwiftUI 表格加粗

是否可以在 SwiftUI 中将 Button<Text> 添加到 Text 中?