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

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

我目前有:

Text("Coronavirus Disease of 2019")

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

【问题讨论】:

    标签: swift xcode swiftui


    【解决方案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" 这样的字符串,那么就可以删除换行符。我认为正则表达式正在删除换行符?
            猜你喜欢
            • 2014-01-16
            • 2012-09-02
            • 2020-05-15
            • 1970-01-01
            • 2017-01-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多