Jak mogę połączyć NSAttributedStrings?

158

Muszę przeszukać niektóre ciągi i ustawić niektóre atrybuty przed scaleniem ciągów, więc posiadanie NSStrings -> Concatenate je -> Make NSAttributedString nie jest opcją, czy istnieje sposób, aby połączyć atrybuty atrybutu z innym ciągiem atrybutu?

Imanou Petit
źródło
13
To śmieszne, jak trudne jest to nadal w sierpniu 2016 r.
Wedge Martin,
17
Nawet w 2018 roku ...
DehMotth
11
jeszcze w 2019;)
raistlin 28.02.19
8
jeszcze w 2020 ...
Hwangho Kim

Odpowiedzi:

210

Zalecałbym użycie pojedynczego przypisywanego ciągu znaków, który zasugerował @Linuxios, a oto kolejny przykład:

NSMutableAttributedString *mutableAttString = [[NSMutableAttributedString alloc] init];

NSString *plainString = // ...
NSDictionary *attributes = // ... a dictionary with your attributes.
NSAttributedString *newAttString = [[NSAttributedString alloc] initWithString:plainString attributes:attributes];

[mutableAttString appendAttributedString:newAttString];

Jednak tylko po to, aby uzyskać wszystkie dostępne opcje, możesz również utworzyć pojedynczy zmienny przypisany ciąg, utworzony ze sformatowanego ciągu NSString zawierającego ciągi wejściowe już zebrane. Następnie możesz użyć, addAttributes: range:aby dodać atrybuty po fakcie do zakresów zawierających ciągi wejściowe. Polecam jednak ten pierwszy sposób.

Mick MacCallum
źródło
Dlaczego zalecamy dołączanie ciągów znaków zamiast dodawania atrybutów?
ma11hew28
86

Jeśli używasz języka Swift, możesz po prostu przeciążać +operator, aby można było je łączyć w ten sam sposób, w jaki łączysz zwykłe ciągi:

// concatenate attributed strings
func + (left: NSAttributedString, right: NSAttributedString) -> NSAttributedString
{
    let result = NSMutableAttributedString()
    result.append(left)
    result.append(right)
    return result
}

Teraz możesz je połączyć, po prostu dodając je:

let helloworld = NSAttributedString(string: "Hello ") + NSAttributedString(string: "World")
glony
źródło
5
klasa zmienna jest podtypem klasy niezmiennej.
glonów
4
Zmiennego podtypu można używać w dowolnym kontekście, który oczekuje niezmiennego typu nadrzędnego, ale nie odwrotnie. Możesz chcieć przejrzeć podklasy i dziedziczenie.
glony
6
Tak, powinieneś zrobić kopię obronną, jeśli chcesz się bronić. (Nie sarkazm.)
algal
1
Jeśli naprawdę chcesz zwrócić NSAttributedString, być może to zadziała:return NSAttributedString(attributedString: result)
Alex
2
@ n13 Utworzyłbym folder o nazwie Helperslub Extensionsi umieściłbym tę funkcję w pliku o nazwie NSAttributedString+Concatenate.swift.
David Lawson
34

Swift 3: Po prostu utwórz NSMutableAttributedString i dołącz do nich przypisane ciągi.

let mutableAttributedString = NSMutableAttributedString()

let boldAttribute = [
    NSFontAttributeName: UIFont(name: "GothamPro-Medium", size: 13)!,
    NSForegroundColorAttributeName: Constants.defaultBlackColor
]

let regularAttribute = [
    NSFontAttributeName: UIFont(name: "Gotham Pro", size: 13)!,
    NSForegroundColorAttributeName: Constants.defaultBlackColor
]

let boldAttributedString = NSAttributedString(string: "Warning: ", attributes: boldAttribute)
let regularAttributedString = NSAttributedString(string: "All tasks within this project will be deleted.  If you're sure you want to delete all tasks and this project, type DELETE to confirm.", attributes: regularAttribute)
mutableAttributedString.append(boldAttributedString)
mutableAttributedString.append(regularAttributedString)

descriptionTextView.attributedText = mutableAttributedString

swift5 upd:

    let captionAttribute = [
        NSAttributedString.Key.font: Font.captionsRegular,
        NSAttributedString.Key.foregroundColor: UIColor.appGray
    ]
Josh O'Connor
źródło
25

Spróbuj tego:

NSMutableAttributedString* result = [astring1 mutableCopy];
[result appendAttributedString:astring2];

Gdzie astring1i astring2NSAttributedStrings.

Linuxios
źródło
13
Lub [[aString1 mutableCopy] appendAttributedString: aString2].
JWWalker
@JWWalker Twój „oneliner” jest uszkodzony. nie można uzyskać tego wyniku „konkatenacji”, ponieważ funkcja appendAttributedString nie zwraca ciągu. Ta sama historia ze słownikami
gaussblurinc
@gaussblurinc: słuszna uwaga, oczywiście twoja krytyka dotyczy również odpowiedzi, którą komentujemy. Tak powinno być NSMutableAttributedString* aString3 = [aString1 mutableCopy]; [aString3 appendAttributedString: aString2];.
JWWalker
@gaussblurinc, JWalker: Poprawiono odpowiedź.
Linuxios
@Linuxios, również wrócisz resultjako NSMutableAttributedString. nie jest tym, co autor chce zobaczyć. stringByAppendingString- ta metoda będzie dobra
gaussblurinc
5

2020 | SWIFT 5.1:

Możesz dodać 2 NSMutableAttributedStringw następujący sposób:

let concatenated = NSAttrStr1.append(NSAttrStr2)

Inny sposób działa z obydwoma NSMutableAttributedStringi NSAttributedString:

[NSAttrStr1, NSAttrStr2].joinWith(separator: "")

Innym sposobem jest ...

var full = NSAttrStr1 + NSAttrStr2 + NSAttrStr3

i:

var full = NSMutableAttributedString(string: "hello ")
// NSAttrStr1 == 1


full += NSAttrStr1 // full == "hello 1"       
full += " world"   // full == "hello 1 world"

Możesz to zrobić za pomocą następującego rozszerzenia:

// works with NSAttributedString and NSMutableAttributedString!
public extension NSAttributedString {
    static func + (left: NSAttributedString, right: NSAttributedString) -> NSAttributedString {
        let leftCopy = NSMutableAttributedString(attributedString: left)
        leftCopy.append(right)
        return leftCopy
    }

    static func + (left: NSAttributedString, right: String) -> NSAttributedString {
        let leftCopy = NSMutableAttributedString(attributedString: left)
        let rightAttr = NSMutableAttributedString(string: right)
        leftCopy.append(rightAttr)
        return leftCopy
    }

    static func + (left: String, right: NSAttributedString) -> NSAttributedString {
        let leftAttr = NSMutableAttributedString(string: left)
        leftAttr.append(right)
        return leftAttr
    }
}

public extension NSMutableAttributedString {
    static func += (left: NSMutableAttributedString, right: String) -> NSMutableAttributedString {
        let rightAttr = NSMutableAttributedString(string: right)
        left.append(rightAttr)
        return left
    }

    static func += (left: NSMutableAttributedString, right: NSAttributedString) -> NSMutableAttributedString {
        left.append(right)
        return left
    }
}
Andrzej
źródło
2
Używam Swift 5.1 i nie mogę po prostu dodać dwóch NSAttrStrings razem ...
PaulDoesDev
1
Dziwne. W tym przypadku po prostu użyjNSAttrStr1.append(NSAttrStr2)
Andrew
Zaktualizowałem moją odpowiedź o rozszerzenia, aby dodać tylko dwa NSAttrStrings :)
Andrew,
4

Jeśli używasz Cocoapods, alternatywą dla obu powyższych odpowiedzi, które pozwalają uniknąć zmienności we własnym kodzie, jest użycie doskonałej kategorii NSAttributedString + CCLFormat na NSAttributedStrings, która pozwala napisać coś takiego:

NSAttributedString *first = ...;
NSAttributedString *second = ...;
NSAttributedString *combined = [NSAttributedString attributedStringWithFormat:@"%@%@", first, second];

Oczywiście używa się go tylko NSMutableAttributedStringpod kołdrą.

Ma również tę dodatkową zaletę, że jest pełnoprawną funkcją formatowania - może więc zrobić o wiele więcej niż dołączanie ciągów do siebie.

fatuhoku
źródło
1
// Immutable approach
// class method

+ (NSAttributedString *)stringByAppendingString:(NSAttributedString *)append toString:(NSAttributedString *)string {
  NSMutableAttributedString *result = [string mutableCopy];
  [result appendAttributedString:append];
  NSAttributedString *copy = [result copy];
  return copy;
}

//Instance method
- (NSAttributedString *)stringByAppendingString:(NSAttributedString *)append {
  NSMutableAttributedString *result = [self mutableCopy];
  [result appendAttributedString:append];
  NSAttributedString *copy = [result copy];
  return copy;
}
gaussblurinc
źródło
1

Możesz spróbować SwiftyFormat Używa następującej składni

let format = "#{{user}} mentioned you in a comment. #{{comment}}"
let message = NSAttributedString(format: format,
                                 attributes: commonAttributes,
                                 mapping: ["user": attributedName, "comment": attributedComment])
Igor Palaguta
źródło
1
Czy możesz go bardziej rozwinąć? Jak to działa?
Kandhal Bhutiya