5

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?)

milohoffman
  • 287
  • 1
  • 11
  • 1
    Could you show a screenshot what you get? Or maybe sample project to reproduce the issue? I try your code and image represents like character in same line without whitespaces. – Anton Vlasov May 12 '19 at 09:18
  • Hey Anton, I added a screenshot and tried to do a better job of describing the problem. It doesn't show any whitespaces, the problem is that it treats the NSTextAttachment as whitespace / a new word for the purpose of word wrapping, and I want the text ahead of it ("testtt" in the example above), to get wrapped with the image. – milohoffman May 13 '19 at 15:50

2 Answers2

4

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.

Gustavo Conde
  • 927
  • 12
  • 20
0

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)
AtulParmar
  • 4,358
  • 1
  • 24
  • 45