J'ai un UILabel
que j'ai créé par programme comme:
var label = UILabel()
J'ai ensuite déclaré un style pour l'étiquette, notamment une police, telle que:
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)
La première partie de l'étiquette se lira toujours: "Filter:"
suivi de l'autre partie de la chaîne, par exemple, "Le plus populaire".
Je voudrais que le filtre Word soit en gras, pour que tout se présente comme suit:
Filtre: Les plus populaires
Je veux le moyen le plus simple de créer cet effet. J'ai cherché sur Internet comment y parvenir et il y a tellement de façons, dont certaines ressemblent à des pages de code. Et la majeure partie semble être en Objective-C. Je le voudrais dans Swift s'il vous plait :)
Je ne sais pas si je suis sur la bonne voie, mais est-ce ce que NSRange
peut aider à atteindre? Merci d'avance
Mettre à jour
J'utilise une série d'instructions if
pour modifier ma variable label
. Tel que:
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"
}
Vous voudrez utiliser attributedString
qui vous permet de styler des parties d'une chaîne, etc. Pour cela, vous pouvez utiliser deux styles, l'un normal, l'autre gras, puis les associer:
let boldText = "Filter:"
let attrs = [NSFontAttributeName : UIFont.boldSystemFontOfSize(15)]
let attributedString = NSMutableAttributedString(string:boldText, attributes:attrs)
let normalText = "Hi am normal"
let normalString = NSMutableAttributedString(string:normalText)
attributedString.appendAttributedString(normalString)
Lorsque vous souhaitez l'assigner à une étiquette:
label.attributedText = attributedString
Vous pouvez utiliser NSMutableAttributedString et NSAttributedString pour créer une chaîne personnalisée. La fonction ci-dessous met en gras boldString en gras dans une chaîne donnée.
Swift 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
}
Exemple d'utilisation
authorLabel.attributedText = attributedText(withString: String(format: "Author : %@", user.name), boldString: "Author", font: authorLabel.font)
Swift 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
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
}
Résultat:
Swift 4.2:
Tout d'abord, nous créons un protocole que UILabel
et UITextField
peuvent adopter.
public protocol ChangableFont: AnyObject {
var text: String? { get set }
var attributedText: NSAttributedString? { get set }
var rangedAttributes: [RangedAttributes] { get }
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)
}
Nous voulons pouvoir ajouter plusieurs modifications à notre texte, nous créons donc la propriété rangedAttributes
. C'est une structure personnalisée qui contient les attributs et la plage dans laquelle ils sont appliqués.
public struct RangedAttributes {
let attributes: [NSAttributedString.Key: Any]
let range: NSRange
public init(_ attributes: [NSAttributedString.Key: Any], inRange range: NSRange) {
self.attributes = attributes
self.range = range
}
}
Un autre problème est que UILabel
sa propriété font
est forte et UITextField
sa propriété font
est faible/facultative. Pour les faire fonctionner avec notre protocole ChangableFont
, nous incluons la méthode getFont() -> UIFont?
.
extension UILabel: ChangableFont {
public func getFont() -> UIFont? {
return font
}
}
extension UITextField: ChangableFont {
public func getFont() -> UIFont? {
return font
}
}
Nous pouvons maintenant aller de l'avant et créer l'implémentation par défaut pour UILabel
et UITextField
en étendant notre protocole.
public extension ChangableFont {
public var rangedAttributes: [RangedAttributes] {
guard let attributedText = attributedText 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
}
public func changeFont(ofText text: String, with font: UIFont) {
guard let range = (self.attributedText?.string ?? self.text)?.range(ofText: text) else { return }
changeFont(inRange: range, with: font)
}
public func changeFont(inRange range: NSRange, with font: UIFont) {
add(attributes: [.font: font], inRange: range)
}
public func changeTextColor(ofText text: String, with color: UIColor) {
guard let range = (self.attributedText?.string ?? self.text)?.range(ofText: text) else { return }
changeTextColor(inRange: range, with: color)
}
public 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 = attributedText {
attributedString = NSMutableAttributedString(attributedString: attributedText)
} else if let text = text {
attributedString = NSMutableAttributedString(string: text)
} else {
return
}
rangedAttributes.append(RangedAttributes(attributes, inRange: range))
rangedAttributes.forEach { (rangedAttributes) in
attributedString.addAttributes(
rangedAttributes.attributes,
range: rangedAttributes.range
)
}
attributedText = attributedString
}
}
Avec l’implémentation par défaut, j’utilise une petite méthode d’aide pour obtenir la NSRange
d’une substring
.
public extension String {
public func range(ofText text: String) -> NSRange {
let fullText = self
let range = (fullText as NSString).range(of: text)
return range
}
}
Avaient fini! Vous pouvez maintenant changer des parties du texte, sa police et sa couleur.
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 :
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
Je partage juste ma propre implémentation assez flexible dans Swift 4.0. Parce qu'il existe certaines conditions, comme la mienne actuellement, pour lesquelles vous devez définir non seulement les caractères gras, mais aussi les caractères italiques dans le texte d'une étiquette.
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
}
}
Vous pouvez faire directement sur String si vous préférez:
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")
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
}