简体   繁体   English

在 Swift 中将 UILabel 的一部分设为粗体

[英]Make part of a UILabel bold in Swift

I have a UILabel I've made programmatically as:我有一个UILabel我以编程方式制作为:

var label = UILabel()

I've then declared some styling for the label, including a font, such as:然后,我为标签声明了一些样式,包括字体,例如:

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)

The first part of the label will always read : "Filter:" then followed by another part of the string, for example, "Most popular"标签的第一部分将始终为: "Filter:"然后是字符串的另一部分,例如,“最流行”

I would like the word filter to be in bold, so the whole thing would look like:我希望过滤器这个词是粗体的,所以整个事情看起来像:

Filter: Most popular过滤器:最受欢迎

I want to simplest way of creating this effect.我想用最简单的方法来创造这种效果。 I've been searching the internet for how to achieve this and there are so many ways, some which just look like pages of code.我一直在互联网上搜索如何实现这一点,有很多方法,有些看起来就像代码页。 And most of it seems to be in Objective-C.其中大部分似乎都在 Objective-C 中。 I would like it in Swift please :)我想在 Swift 中使用它 :)

I don't know if i'm on the right lines, but is this what NSRange can help achieve?我不知道我是否在正确的路线上,但这是NSRange可以帮助实现的目标吗? Thanks in advance提前致谢

Update更新

I use a series of if statements to change my label variable.我使用一系列if语句来更改我的label变量。 Such as:如:

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"

}

You will want to use attributedString which allows you to style parts of a string etc. This can be done like this by having two styles, one normal, one bold, and then attaching them together:您将需要使用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)

When you want to assign it to a label:当您想将其分配给标签时:

label.attributedText = attributedString

You can use NSMutableAttributedString and NSAttributedString to create customized string.您可以使用 NSMutableAttributedString 和 NSAttributedString 来创建自定义字符串。 The function below makes given boldString bold in given string.下面的函数使给定的 boldString 在给定的字符串中加粗。

Swift 3斯威夫特 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
}

Example usage示例用法

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

Swift 4斯威夫特 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 and 5斯威夫特 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
}

Result:结果:

在此处输入图片说明

Swift 4.2 & 5.0:斯威夫特 4.2 和 5.0:

First off we create a protocol that UILabel , UITextField and UITextView can adopt.首先,我们创建了一个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()
}

We want to be able to add multiple changes to our text, therefore we create the rangedAttributes property.我们希望能够为我们的文本添加多个更改,因此我们创建了rangedAttributes属性。 It's a custom struct that holds attributes and the range in which they are applied.它是一个自定义结构,包含属性和应用它们的范围。

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
    }
}

Another problem is that UILabel its font property is strong and UITextField its font property is weak/optional.另一个问题是UILabelfont属性很强,而UITextFieldfont属性很弱/可选。 To make them both work with our ChangableFont protocol we include the getFont() -> UIFont?为了让它们都与我们的ChangableFont协议一起工作,我们包含了getFont() -> UIFont? method.方法。 This also counts for UITextView its text and attributedText properties.这也计算 UITextView 的textattributedText text attributedText That's why we implement the getter and setter methods for them as well.这就是我们为它们实现 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
    }
}

Now we can go ahead and create the default implementation for UILabel , UITextField and UITextView by extending our protocol.现在我们可以继续通过扩展我们的协议为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))
    }
}

With in the default implementation I use a little helper method for getting the NSRange of a substring .在默认实现中,我使用了一个小助手方法来获取substringNSRange

public extension String {

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

We're done!我们完成了! You can now change parts of the text its font and text color.您现在可以更改部分文本的字体和文本颜色。

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)

Swift 4 alternative : 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

You can directly do on String if you prefer:如果你愿意,你可以直接在 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
}}

Usage:用法:

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

Just sharing my own quite-flexible implementation in Swift 4.0.只是在 Swift 4.0 中分享我自己的非常灵活的实现。 Cause there are some requirements, like mine currently, that you need to set not only bold but italic the part of a label's text.因为有一些要求,例如我目前的要求,您不仅需要将标签文本的部分设置为粗体,还需要设置为斜体。

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
    }
}

for the ones who prefer extensions对于喜欢扩展的人

Swift 5.0斯威夫特 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
    }

and use:并使用:

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

Swift 4.0 solution 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
}

在此处输入图片说明

If you know which character place values you want to bold I created a function which takes ranges of characters and optional fonts (use nil if you just want to use the standard system font of size 12), and returns an NSAttributedString which you can attach to a label as its attributed text.如果您知道要加粗的字符位置值,我创建了一个函数,该函数接受字符范围和可选字体(如果您只想使用大小为 12 的标准系统字体,请使用 nil),并返回一个 NSAttributedString,您可以将其附加到一个标签作为其属性文本。 I wanted to bolden the 0th, 10th, 22-23rd, 30th and 34th characters of my string so i used [[0,0], [10,10], [22,23], [30,30], [34,34]] for my boldCharactersRanges value.我想加粗字符串的第 0、10、22-23、30 和 34 个字符,所以我使用了 [[0,0], [10,10], [22,23], [30,30], [34] ,34]] 用于我的 boldCharactersRanges 值。

Usage:用法:

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)
}

If you're using XCode 13 and want to do it from the storyboard then follow these steps.如果您使用的是XCode 13并希望从故事板中执行此操作,请按照以下步骤操作。

  1. Select the attributed instead of plain here.在这里选择属性而不是普通 Further, you can select the part of your text and set the size, font, and other properties of the text.此外,您可以选择文本的一部分并设置文本的大小、字体和其他属性。 Note that in case you want to set the custom font then make sure you install it first.请注意,如果您想设置自定义字体,请确保先安装它。

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM