【问题标题】:Make part of a UILabel bold in Swift在 Swift 中使 UILabel 的一部分变为粗体
【发布时间】:2016-07-28 23:01:29
【问题描述】:

我有一个UILabel 我以编程方式制作为:

var label = UILabel()

然后我为标签声明了一些样式,包括字体,例如:

label.frame = CGRect(x: 20, y: myHeaderView.frame.height / 2, width: 300, height: 30)
label.font = UIFont(name: "Typo GeoSlab Regular Demo", size: 15)
label.textColor = UIColor(hue: 0/360, saturation: 0/100, brightness: 91/100, alpha: 1)

标签的第一部分将始终显示为:"Filter:",然后是字符串的另一部分,例如“最受欢迎”

我希望过滤器这个词用粗体显示,所以整个事情看起来像:

过滤器:最受欢迎

我想用最简单的方法来制作这种效果。我一直在互联网上搜索如何实现这一点,有很多方法,有些看起来像代码页。而且大部分似乎都在Objective-C中。我想在 Swift 中使用它:)

我不知道我是否在正确的路线上,但这就是NSRange 可以帮助实现的目标吗?提前致谢

更新

我使用一系列if 语句来更改我的label 变量。如:

if indexArray == 1 {

    label.text = "Filter: Film name"

} else if indexArray == 2 {

    label.text = "Filter: Most popular"

} else if indexArray == 3 {

    label.text = "Filter: Star rating"

}

【问题讨论】:

    标签: ios string swift uilabel nsrange


    【解决方案1】:

    您将需要使用attributedString,它允许您设置字符串的部分样式等。这可以通过使用两种样式来完成,一种是普通的,一种是粗体的,然后将它们附加在一起:

    let boldText = "Filter:"
    let attrs = [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 15)]
    let attributedString = NSMutableAttributedString(string:boldText, attributes:attrs)
    
    let normalText = "Hi am normal"
    let normalString = NSMutableAttributedString(string:normalText)
    
    attributedString.append(normalString)
    

    当您想将其分配给标签时:

    label.attributedText = attributedString
    

    【讨论】:

    • 感谢您的回答!它似乎确实有效。不过,我需要修改。如果我需要 normalText 根据索引计数成为不同的字符串,我将如何处理。请参阅我的问题的 更新 部分。提前致谢!
    • 您可以将 normalText 从数组中拉出并通过索引获取它: normalText = normalTextArray[index] 这就像 let normalTextArray = ["Hello", "Two", "Three"]
    • Value of type 'String' has no member 'appendAttributedString'
    • @ScottyBlades 对于较新版本的 Swift,请使用 attributedString.append(normalString)
    【解决方案2】:

    您可以使用 NSMutableAttributedString 和 NSAttributedString 来创建自定义字符串。下面的函数使给定的粗体字符串在给定的字符串中变为粗体。

    斯威夫特 3

    func attributedText(withString string: String, boldString: String, font: UIFont) -> NSAttributedString {
        let attributedString = NSMutableAttributedString(string: string,
                                                         attributes: [NSFontAttributeName: font])
        let boldFontAttribute: [String: Any] = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: font.pointSize)]
        let range = (string as NSString).range(of: boldString)
        attributedString.addAttributes(boldFontAttribute, range: range)
        return attributedString
    }
    

    示例用法

    authorLabel.attributedText = attributedText(withString: String(format: "Author : %@", user.name), boldString: "Author", font: authorLabel.font)
    

    斯威夫特 4

    func attributedText(withString string: String, boldString: String, font: UIFont) -> NSAttributedString {
        let attributedString = NSMutableAttributedString(string: string,
                                                         attributes: [NSAttributedStringKey.font: font])
        let boldFontAttribute: [NSAttributedStringKey: Any] = [NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: font.pointSize)]
        let range = (string as NSString).range(of: boldString)
        attributedString.addAttributes(boldFontAttribute, range: range)
        return attributedString
    }
    

    Swift 4.2 和 5

    func attributedText(withString string: String, boldString: String, font: UIFont) -> NSAttributedString {
        let attributedString = NSMutableAttributedString(string: string,
                                                     attributes: [NSAttributedString.Key.font: font])
        let boldFontAttribute: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: font.pointSize)]
        let range = (string as NSString).range(of: boldString)
        attributedString.addAttributes(boldFontAttribute, range: range)
        return attributedString
    }
    

    【讨论】:

    • 效果很好,这应该是公认的答案。
    • 使范围搜索不区分大小写也可能有帮助let range = (self as NSString).range(of: boldString, options: CompareOptions.caseInsensitive)
    【解决方案3】:

    Swift 4 替代方案

    let attrs = [NSAttributedStringKey.font : UIFont.boldSystemFont(ofSize: 14)]
    let attributedString = NSMutableAttributedString(string: "BOLD TEXT", attributes:attrs)
    let normalString = NSMutableAttributedString(string: "normal text")
    attributedString.append(normalString)
    myLabel.attributedText = attributedString
    

    【讨论】:

      【解决方案4】:

      只是分享我自己在 Swift 4.0 中相当灵活的实现。因为有一些要求,比如我目前的要求,您不仅需要将标签文本的部分设置为粗体,还需要设置斜体。

      import UIKit
      
      extension UILabel {
      
          /** Sets up the label with two different kinds of attributes in its attributed text.
           *  @params:
           *  - primaryString: the normal attributed string.
           *  - secondaryString: the bold or highlighted string.
           */
      
          func setAttributedText(primaryString: String, textColor: UIColor, font: UIFont, secondaryString: String, secondaryTextColor: UIColor, secondaryFont: UIFont) {
      
              let completeString = "\(primaryString) \(secondaryString)"
      
              let paragraphStyle = NSMutableParagraphStyle()
              paragraphStyle.alignment = .center
      
              let completeAttributedString = NSMutableAttributedString(
                  string: completeString, attributes: [
                      .font: font,
                      .foregroundColor: textColor,
                      .paragraphStyle: paragraphStyle
                  ]
              )
      
              let secondStringAttribute: [NSAttributedStringKey: Any] = [
                  .font: secondaryFont,
                  .foregroundColor: secondaryTextColor,
                  .paragraphStyle: paragraphStyle
              ]
      
              let range = (completeString as NSString).range(of: secondaryString)
      
              completeAttributedString.addAttributes(secondStringAttribute, range: range)
      
              self.attributedText = completeAttributedString
          }
      }
      

      【讨论】:

        【解决方案5】:

        结果:

        Swift 4.2 和 5.0:

        首先,我们创建一个UILabelUITextFieldUITextView 可以采用的协议。

        public protocol ChangableFont: AnyObject {
            var rangedAttributes: [RangedAttributes] { get }
            func getText() -> String?
            func set(text: String?)
            func getAttributedText() -> NSAttributedString?
            func set(attributedText: NSAttributedString?)
            func getFont() -> UIFont?
            func changeFont(ofText text: String, with font: UIFont)
            func changeFont(inRange range: NSRange, with font: UIFont)
            func changeTextColor(ofText text: String, with color: UIColor)
            func changeTextColor(inRange range: NSRange, with color: UIColor)
            func resetFontChanges()
        }
        

        我们希望能够为我们的文本添加多个更改,因此我们创建了rangedAttributes 属性。它是一个自定义结构,包含属性及其应用范围。

        public struct RangedAttributes {
        
            public let attributes: [NSAttributedString.Key: Any]
            public let range: NSRange
        
            public init(_ attributes: [NSAttributedString.Key: Any], inRange range: NSRange) {
                self.attributes = attributes
                self.range = range
            }
        }
        

        另一个问题是UILabelfont 属性很强大,而UITextFieldfont 属性很弱/可选。为了使它们都与我们的ChangableFont 协议一起工作,我们包含了getFont() -> UIFont? 方法。这对于 UITextView 的 textattributedText 属性也很重要。这也是我们为它们实现 getter 和 setter 方法的原因。

        extension UILabel: ChangableFont {
        
            public func getText() -> String? {
                return text
            }
        
            public func set(text: String?) {
                self.text = text
            }
        
            public func getAttributedText() -> NSAttributedString? {
                return attributedText
            }
        
            public func set(attributedText: NSAttributedString?) {
                self.attributedText = attributedText
            }
        
            public func getFont() -> UIFont? {
                return font
            }
        }
        
        extension UITextField: ChangableFont {
        
            public func getText() -> String? {
                return text
            }
        
            public func set(text: String?) {
                self.text = text
            }
        
            public func getAttributedText() -> NSAttributedString? {
                return attributedText
            }
        
            public func set(attributedText: NSAttributedString?) {
                self.attributedText = attributedText
            }
        
            public func getFont() -> UIFont? {
                return font
            }
        }
        
        extension UITextView: ChangableFont {
        
            public func getText() -> String? {
                return text
            }
        
            public func set(text: String?) {
                self.text = text
            }
        
            public func getAttributedText() -> NSAttributedString? {
                return attributedText
            }
        
            public func set(attributedText: NSAttributedString?) {
                self.attributedText = attributedText
            }
        
            public func getFont() -> UIFont? {
                return font
            }
        }
        

        现在我们可以通过扩展我们的协议继续为UILabelUITextFieldUITextView 创建默认实现。

        public extension ChangableFont {
        
            var rangedAttributes: [RangedAttributes] {
                guard let attributedText = getAttributedText() else {
                    return []
                }
                var rangedAttributes: [RangedAttributes] = []
                let fullRange = NSRange(
                    location: 0,
                    length: attributedText.string.count
                )
                attributedText.enumerateAttributes(
                    in: fullRange,
                    options: []
                ) { (attributes, range, stop) in
                    guard range != fullRange, !attributes.isEmpty else { return }
                    rangedAttributes.append(RangedAttributes(attributes, inRange: range))
                }
                return rangedAttributes
            }
        
            func changeFont(ofText text: String, with font: UIFont) {
                guard let range = (self.getAttributedText()?.string ?? self.getText())?.range(ofText: text) else { return }
                changeFont(inRange: range, with: font)
            }
        
            func changeFont(inRange range: NSRange, with font: UIFont) {
                add(attributes: [.font: font], inRange: range)
            }
        
            func changeTextColor(ofText text: String, with color: UIColor) {
                guard let range = (self.getAttributedText()?.string ?? self.getText())?.range(ofText: text) else { return }
                changeTextColor(inRange: range, with: color)
            }
        
            func changeTextColor(inRange range: NSRange, with color: UIColor) {
                add(attributes: [.foregroundColor: color], inRange: range)
            }
        
            private func add(attributes: [NSAttributedString.Key: Any], inRange range: NSRange) {
                guard !attributes.isEmpty else { return }
        
                var rangedAttributes: [RangedAttributes] = self.rangedAttributes
        
                var attributedString: NSMutableAttributedString
        
                if let attributedText = getAttributedText() {
                    attributedString = NSMutableAttributedString(attributedString: attributedText)
                } else if let text = getText() {
                    attributedString = NSMutableAttributedString(string: text)
                } else {
                    return
                }
        
                rangedAttributes.append(RangedAttributes(attributes, inRange: range))
        
                rangedAttributes.forEach { (rangedAttributes) in
                    attributedString.addAttributes(
                        rangedAttributes.attributes,
                        range: rangedAttributes.range
                    )
                }
        
                set(attributedText: attributedString)
            }
        
            func resetFontChanges() {
                guard let text = getText() else { return }
                set(attributedText: NSMutableAttributedString(string: text))
            }
        }
        

        在默认实现中,我使用一个小助手方法来获取NSRangesubstring

        public extension String {
        
            func range(ofText text: String) -> NSRange {
                let fullText = self
                let range = (fullText as NSString).range(of: text)
                return range
            }
        }
        

        我们完成了!您现在可以更改部分文本的字体和文本颜色。

        titleLabel.text = "Welcome"
        titleLabel.font = UIFont.systemFont(ofSize: 70, weight: .bold)
        titleLabel.textColor = UIColor.black
        titleLabel.changeFont(ofText: "lc", with: UIFont.systemFont(ofSize: 60, weight: .light))
        titleLabel.changeTextColor(ofText: "el", with: UIColor.blue)
        titleLabel.changeTextColor(ofText: "co", with: UIColor.red)
        titleLabel.changeTextColor(ofText: "m", with: UIColor.green)
        

        【讨论】:

        • 感谢这个解决方案!您可以将其发布为 CocoaPods 库。
        • 谢谢,很高兴能为您提供帮助。哈哈很棒的建议。
        • 哇,完美。谢谢
        • @LloydKeijzer 为 UITextView 做什么?
        • @pradipsutariya 我很高兴它能正常工作。关于您的问题,应该可以通过提取文本中所有链接的范围(NSRange)来实现。提取后,您可以遍历范围集合并调用 func changeFont(inRange range: NSRange, with font: UIFont)func changeTextColor(inRange range: NSRange, with color: UIColor)
        【解决方案6】:

        Swift 4.0 解决方案

        let font = UIFont.systemFont(ofSize: 14)
        
        func boldSearchResult(searchString: String, resultString: String) -> NSMutableAttributedString {
            let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: resultString)
        
            guard let regex  = try? NSRegularExpression(pattern: searchString.lowercased(), options: []) else {
                return attributedString
            }
        
            let range: NSRange = NSMakeRange(0, resultString.count)
        
            regex.enumerateMatches(in: resultString.lowercased(), options: [], range: range) { (textCheckingResult, matchingFlags, stop) in
                guard let subRange = textCheckingResult?.range else {
                    return
                }
        
                attributedString.addAttributes([NSAttributedString.Key.font : font], range: subRange)
            }
        
            return attributedString
        }
        

        【讨论】:

          【解决方案7】:

          如果你愿意,你可以直接在 String 上做:

          extension String {
          func withBoldText(text: String, font: UIFont? = nil) -> NSAttributedString {
            let _font = font ?? UIFont.systemFont(ofSize: 14, weight: .regular)
            let fullString = NSMutableAttributedString(string: self, attributes: [NSAttributedString.Key.font: _font])
            let boldFontAttribute: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: _font.pointSize)]
            let range = (self as NSString).range(of: text)
            fullString.addAttributes(boldFontAttribute, range: range)
            return fullString
          }}
          

          用法:

          label.attributeString = "my full string".withBoldText(text: "full")
          

          【讨论】:

          • 必须更改为属性文本才能工作。 titleLabel.attributedText = "我的完整字符串".withBoldText(text: "full")
          • @StefanoPedroli 如何使用自定义字体?
          【解决方案8】:

          对于喜欢扩展的人

          Swift 5.0

              /// will set a regual and a bold text in the same label
              public func setRegualAndBoldText(regualText: String,
                                                 boldiText: String) {
          
                  let attrs = [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: font.pointSize)]
                  let regularString = NSMutableAttributedString(string: regualText)
                  let boldiString = NSMutableAttributedString(string: boldiText, attributes:attrs)
                  regularString.append(boldiString)
                  attributedText = regularString
              }
          

          并使用:

          label.setRegualAndBoldText(regualText: "height: ", boldiText: "1.65 :(")
          

          【讨论】:

            【解决方案9】:

            如果您知道要加粗的字符位置值,我创建了一个函数,该函数采用字符范围和可选字体(如果您只想使用大小为 12 的标准系统字体,请使用 nil),并返回一个 NSAttributedString可以附加到标签作为其属性文本。我想加粗字符串的第 0、10、22-23、30 和 34 个字符,所以我使用了 [[0,0]、[10,10]、[22,23]、[30,30]、[34 ,34]] 用于我的 boldCharactersRanges 值。

            用法:

            func boldenParts(string: String, boldCharactersRanges: [[Int]], regularFont: UIFont?, boldFont: UIFont?) -> NSAttributedString {
                let attributedString = NSMutableAttributedString(string: string, attributes: [NSAttributedString.Key.font: regularFont ?? UIFont.systemFont(ofSize: 12)])
                let boldFontAttribute: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: boldFont ?? UIFont.boldSystemFont(ofSize: regularFont?.pointSize ?? UIFont.systemFontSize)]
                for range in boldCharactersRanges {
                    let currentRange = NSRange(location: range[0], length: range[1]-range[0]+1)
                    attributedString.addAttributes(boldFontAttribute, range: currentRange)
                    }
                return attributedString
            }
            
            override func viewDidLoad() {
                super.viewDidLoad()
                let label = UILabel()
                label.frame = CGRect(x: 0, y: 0, width: 180, height: 50)
                label.numberOfLines = 0
                label.center = view.center
                let text = "Under the pillow is a vogue article"
                let secretMessage = boldenParts(string: text, boldCharactersRanges: [[0,0], [10,10], [22,23], [30,30], [34,34]], regularFont: UIFont(name: "Avenir", size: 15), boldFont: UIFont(name: "Avenir-Black", size: 15))
                label.attributedText = secretMessage
                view.addSubview(label)
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-06-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-07-29
              • 2012-08-18
              • 1970-01-01
              相关资源
              最近更新 更多