milohoffman
milohoffman

Reputation: 295

Getting an image imbedded in an NSAttributedString (via NSTextAttachment) to be treated as a single character, so that it doesn't break lines?

I'm embedding an image in an NSAttributedString, and I want iOS to treat it as a character that is a part of the word before it, so that it doesn't get broken onto its own line. I read somewhere that is supposed to be the default behavior, but for the life of me I can't get it to work. Here's my code (I'm the inserting this attributed string as the title of a button):

    var title = "This is an example string. Test testtt"
    let titleTextString = NSMutableAttributedString(string: title)

    let imageAttachment =  NSTextAttachment()
    imageAttachment.image = UIImage(named:"myIcon")
    imageAttachment.bounds = CGRect(x: 0, y: 1.0, width: 14, height: 6)
    let imageAttachmentString = NSMutableAttributedString(attachment: imageAttachment)


    titleTextString.append(imageAttachmentString)
    button.setAttributedTitle(titleTextString, for: .normal)

Here's an image of what it looks like:

enter image description here

As you can see, there is no whitespace at the end of the string. I am trying to get the label to consider the text attachment a normal non-whitespace character, and thus part of the word "testtt", which would then cause the "testtt" to be word-wrapped (words are otherwise correctly word-wrapped, and I've set word wrapping on both the label and in the paragraph style of the NSAttributedString).

Complicating this matter is that I found the existence of a non-breaking which solve the problem, but forces other parts of the string to be unnecessarily broken. If I append a non-breaking space to the end of the string:

var title = "This is an example string. Test testtt" + "\u{A0}"

I then get the correct breaking behavior, but for some reason the previous word is also unnecessarily broken:

enter image description here

Does anyone have any idea how to get this to behavior correctly (i.e., count the image as any other letter, rather than whitespace?)

Upvotes: 6

Views: 1713

Answers (2)

AtulParmar
AtulParmar

Reputation: 4570

enter image description here

Set button title label text lineBreakMode as .byWordWrapping and textAlignment as .center to get the output as you aspect, See the following code.

let title = "This is an example string. Test testtt"
let titleTextString = NSMutableAttributedString(string: title)

let imageAttachment =  NSTextAttachment()
imageAttachment.image = UIImage(named:"myIcon")
imageAttachment.bounds = CGRect(x: 0, y: 1.0, width: 14, height: 7)
let imageAttachmentString = NSMutableAttributedString(attachment: imageAttachment)


titleTextString.append(imageAttachmentString)
button.titleLabel?.lineBreakMode = .byWordWrapping
button.titleLabel?.textAlignment = .center
button.setAttributedTitle(titleTextString, for: .normal)

Upvotes: 0

Gustavo Conde
Gustavo Conde

Reputation: 977

You can accomplish that by adding a zero-width non-breaking space: \u{FEFF} to the end of your original string.

var title = "This is an example string. Test testtt\u{FEFF}"
let titleTextString = NSMutableAttributedString(string: title)

let imageAttachment =  NSTextAttachment()
imageAttachment.image = UIImage(named:"myIcon")
imageAttachment.bounds = CGRect(x: 0, y: 1.0, width: 14, height: 6)
let imageAttachmentString = NSMutableAttributedString(attachment: imageAttachment)


titleTextString.append(imageAttachmentString)
button.setAttributedTitle(titleTextString, for: .normal)

Credit to this SO question+answer In a UILabel, is it possible to force a line NOT to break in a certain place

EDIT:

To answer your question about wrong word wrapped. You can find the answer here. It's a new behavior for word wrapping introduced by Apple.

Upvotes: 4

Related Questions