Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 201
Brian Nickel Avatar asked Aug 19 '14 21:08

Brian Nickel


3 Answers

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))
like image 50
Brian Nickel Avatar answered Oct 24 '22 05:10

Brian Nickel


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"];
like image 20
PetrV Avatar answered Oct 24 '22 06:10

PetrV


@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}")
    }
}
like image 1
Thomas Besnehard Avatar answered Oct 24 '22 05:10

Thomas Besnehard