ios - Haz parte de una UILabel negrita en Swift
uitextfield swift 4 (7)
Tengo una UILabel
que he hecho programáticamente como:
var label = UILabel()
Luego he declarado algunos estilos para la etiqueta, incluida una fuente, como:
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 primera parte de la etiqueta siempre se leerá: "Filter:"
luego otra parte de la cadena, por ejemplo, "Más popular".
Me gustaría que la palabra filtro esté en negrita, para que todo se vea como:
Filtro: Los más populares
Quiero la forma más sencilla de crear este efecto. He estado buscando en internet cómo lograrlo y hay muchas maneras, algunas de las cuales parecen páginas de código. Y la mayor parte parece estar en Objective-C. Me gustaría en Swift por favor :)
No sé si estoy en la línea correcta, pero ¿es esto lo que NSRange
puede ayudar a lograr? Gracias por adelantado
Actualizar
Utilizo una serie de sentencias if
para cambiar mi variable de label
. Como:
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"
}
Puede usar NSMutableAttributedString y NSAttributedString para crear una cadena personalizada. La siguiente función hace que boldString esté en negrita en una cadena dada.
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
}
Ejemplo de uso
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
}
Puedes hacerlo directamente en String si prefieres:
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
}}
Uso:
label.attributeString = "my full string".withBoldText(text: "full")
Resultado:
Swift 4.2:
En primer lugar, creamos un protocolo que tanto UILabel
como UITextField
pueden adoptar.
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)
}
Queremos poder agregar varios cambios a nuestro texto, por lo tanto, creamos la propiedad rangedAttributes
. Es una estructura personalizada que contiene atributos y el rango en el que se aplican.
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
}
}
Otro problema es que UILabel
su propiedad de font
es fuerte y UITextField
su propiedad de font
es débil / opcional. Para hacer que ambos funcionen con nuestro protocolo ChangableFont
, incluimos getFont() -> UIFont?
método.
extension UILabel: ChangableFont {
public func getFont() -> UIFont? {
return font
}
}
extension UITextField: ChangableFont {
public func getFont() -> UIFont? {
return font
}
}
Ahora podemos seguir adelante y crear la implementación predeterminada para UILabel
y UITextField
al extender nuestro protocolo.
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
}
}
Con la implementación predeterminada, uso un pequeño método auxiliar para obtener el NSRange
de una substring
.
public extension String {
public func range(ofText text: String) -> NSRange {
let fullText = self
let range = (fullText as NSString).range(of: text)
return range
}
}
Hemos terminado Ahora puede cambiar partes del texto, su fuente y color de texto.
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)
Solo compartiendo mi propia implementación bastante flexible en Swift 4.0. Porque hay algunos requisitos, como el mío en la actualidad, de que necesita establecer no solo en negrita sino en cursiva la parte del texto de una etiqueta.
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
}
}
Solución 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
}
Usted querrá usar los attributedString
que le permiten diseñar partes de una cadena, etc. Esto se puede hacer de esta manera al tener dos estilos, uno normal, uno en negrita, y luego unirlos:
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)
Cuando quieras asignarlo a una etiqueta:
label.attributedText = attributedString
Alternativa 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