Subrayar parte de una cadena con NSMutableAttributedString en iOS 8 no funciona
objective-c iphone (7)
Agregue color para el atributo subrayado:
[attributedString addAttribute:NSUnderlineColorAttributeName
value:[UIColor redColor]
range:NSMakeRange(5, 6)];
Intento subrayar parte de una cadena, por ejemplo, una parte ''
cadena
'' en la
cadena
''cadena de
prueba
''.
Estoy usando
NSMutableAttributedString
y mi solución funcionaba bien en
iOS7
.
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]
initWithString:@"test string"];
[attributedString addAttribute:NSUnderlineStyleAttributeName
value:@(NSUnderlineStyleSingle)
range:NSMakeRange(5, 6)];
myLabel.attributedText = attributedString;
El problema es que mi solución ya no funciona en
iOS8
.
Después de pasar una hora probando múltiples variantes de
NSMutableAttributedString
, descubrí que esta solución solo funciona cuando el rango comienza con 0 (la longitud puede diferir).
¿Cuál es la razón para eso?
¿Cómo puedo solucionar esto?
Descubrí que si aplica UnderlineStyleNone a toda la cadena, puede aplicar selectivamente subrayado a una parte que comienza en el medio:
func underlinedString(string: NSString, term: NSString) -> NSAttributedString {
let output = NSMutableAttributedString(string: string)
let underlineRange = string.rangeOfString(term)
output.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleNone.rawValue, range: NSMakeRange(0, string.length))
output.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleSingle.rawValue, range: underlineRange)
return output
}
Es septiembre de 2018, por lo que esta respuesta no se trata de iOS8, pero aún se relaciona con subrayar parte de una cadena.
Aquí hay una extensión de
Swift 4
que subraya un término dado dentro de un
myAttributedString
ya compuesto
extension NSMutableAttributedString {
func underline(term: String) {
guard let underlineRange = string.range(of: term) else {
return
}
let startPosition = string.distance(from: term.startIndex, to: underlineRange.lowerBound)
let nsrange = NSRange(location: startPosition, length: term.count)
addAttribute(
.underlineStyle,
value: NSUnderlineStyle.styleSingle.rawValue,
range: nsrange)
}
}
Uso:
myAttributedString.underline(term: "some term")
Utilicé la siguiente extensión (usando la función de Exidy) en el patio de recreo / simulador y funcionó bien, puede cambiar / agregar atributos según sus necesidades
extension NSMutableAttributedString
{
func changeWordsColour(terms:[NSString])
{
let string = self.string as NSString
self.addAttribute(NSForegroundColorAttributeName, value: UIColor.brownColor(), range: NSMakeRange(0, self.length))
for term in terms
{
let underlineRange = string.rangeOfString(term as String)
self.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: underlineRange)
}
}
}
let myStr = NSMutableAttributedString(string: "Change Words Colour")
myStr.changeWordsColour(["change","Colour"])
Actualización: Al investigar esta pregunta: Mostrar NSMutableAttributedString en iOS 8 ¡Finalmente encontré la solución!
Debe agregar NSUnderlineStyleNone al comienzo de la cadena.
Swift 4.2 (
none
se eliminó
none
):
let attributedString = NSMutableAttributedString()
attributedString.append(NSAttributedString(string: "test ",
attributes: [.underlineStyle: 0]))
attributedString.append(NSAttributedString(string: "s",
attributes: [.underlineStyle: NSUnderlineStyle.single.rawValue]))
attributedString.append(NSAttributedString(string: "tring",
attributes: [.underlineStyle: 0]))
C objetivo:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:@"test "
attributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleNone)}]];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:@"s"
attributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle),
NSBackgroundColorAttributeName: [UIColor clearColor]}]];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:@"tring"]];
Otra ventaja de este enfoque es la ausencia de cualquier rango. Muy agradable para cadenas localizadas.
Parece que es un error de Apple :(
Versión Swift 5 de la respuesta de @ Joss con pocas modificaciones, agregando un NSMutableAttributedString devuelto, porque no podría usar la solución original sin él.
extension NSMutableAttributedString {
func underline(term: String) -> NSMutableAttributedString {
guard let underlineRange = string.range(of: term) else {
return NSMutableAttributedString()
}
let startPosition = string.distance(from: term.startIndex, to: underlineRange.lowerBound)
let nsrange = NSRange(location: startPosition, length: term.count)
addAttribute(
.underlineStyle,
value: NSUnderlineStyle.single.rawValue,
range: nsrange)
return self
}
}
Uso:
let myUnderLinedText = "Hello World"
let underLinedMutableString = NSMutableAttributedString(string: myUnderLinedText, attributes: titleAttributes).underline(term: myUnderLinedText)
NSMutableAttributedString *signUpString = [[NSMutableAttributedString alloc] initWithString:@"Not a member yet?Sign Up now"];
[signUpString appendAttributedString:[[NSAttributedString alloc] initWithString:@" "attributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleNone)}]];
[signUpString addAttributes: @{NSForegroundColorAttributeName:UIColorFromRGB(0x43484B),NSUnderlineStyleAttributeName:[NSNumber numberWithInteger:NSUnderlineStyleSingle]} range:NSMakeRange(17,11)];
signUpLbl.attributedText = [signUpString copy];
Funciono para mi