Brian Nickel
Brian Nickel

Reputation: 27560

Preventing line breaks in part of an NSAttributedString

I am working on a UILabel which features large main text followed by smaller text that tells you who said it:

Screenshot showing problem

Right now it is basically an NSAttributedString with a font attribute on the small text.

I would like to set things up so the big text wraps but the small text doesn't. I.e., If the text will all fit on the same line as it does in the right item, it should render as is, but it it would wrap like in the left item, the whole of the small text should appear on the next line:

Screenshot showing correct behavior

The HTML equivalent of what I'm trying to achieve is:

Title <nobr>Subtitle</nobr>
- or -
Title <span style="white-space:nowrap">Subtitle</span>

I've tried converting both of these to NSAttributedStrings with NSHTMLTextDocumentType and it doesn't appear to do a direct translation.

Upvotes: 18

Views: 5600

Answers (3)

Thomas Besnehard
Thomas Besnehard

Reputation: 2095

@brian-nickel great solution in Swift 5.1 and in a String extension

extension String {
    var withoutLineBreak: String {
        self.replacingOccurrences(of: " ", with: "\u{a0}")
            .replacingOccurrences(of: "-", with: "\u{2011}")
    }
}

Upvotes: 4

Brian Nickel
Brian Nickel

Reputation: 27560

Following rmaddy's suggestion, I was able to get the effect I wanted by replacing spaces and dashes with their non-breaking alternatives:

Objective-C:

NS_INLINE NSString *NOBR(NSString *string) {
return [[string stringByReplacingOccurrencesOfString:@" " withString:@"\u00a0"] 
                stringByReplacingOccurrencesOfString:@"-" withString:@"\u2011"];

}

NSAttributedString *username = [[NSAttributedString alloc] 
    initWithString:NOBR(hotQuestion.username) attributes:nil];
...

Swift (note the slightly different escape code format):

func nobr(_ string:String) -> String {
    return string
        .stringByReplacingOccurrencesOfString(" ", withString: "\u{a0}")
        .stringByReplacingOccurrencesOfString("-", withString: "\u{2011}")
}

let username = NSAttributedString(string:nobr(hotQuestion.username, attributes:nil))

Upvotes: 34

PetrV
PetrV

Reputation: 1368

There is also word-joiner \u2060 character in Unicode which will prevent line break on its either side and is invisible. I used it to force word wrap when degree sign was part of word, so the whole word will stay on the same line, in iOS.

Objective-C:

text = [text stringByReplacingOccurrencesOfString:@"°" withString:@"\u2060°\u2060"];

Upvotes: 16

Related Questions