Michael Woyo Michael Woyo - 6 months ago 7x
Swift Question

Combining text and images in `UITextView`

Before I begin, let me acknowledge that similar questions exist, some with answers, others without. However, they do not address my specific problem. If you know of any, please refer me.

Now, when I add images to the

, I place the images at the point where the cursor is. I achieve this by appending 5 spaces each time to make room for the image. When the cursor gets to the end of the
, it stays there without moving automatically to the next line unless I type a key. Even when I append spaces, it still stays there so my images just pile up there. I decided to add a line-break
to move it to the next line manually.
Now I have two problems. First, only part of the images at the corner display even though I have a condition like:

if ((cursorPosition.x + 30) >= message.frame.width) {

message.text = message.text.stringByAppendingString("\n");
else {
message.text = message.text.stringByAppendingString(" ");

How do I fix this to make it not go out of the frame?

Secondly, because am adding new line manually, when I delete a text, the cursor moves to some arbitrary position which is quite weird to me. Example, I could be deleting text on line 4 but it will just jump to line 2.
Any suggestion on how to solve either or both would be very much appreciated. Below is how the
looks like:

Edited: I am editing this to help anyone who may have a similar problem. I wanted to create an app where users add text and images together like we do in
for example. I struggled to do this until the solution below was suggested to me. It works great. Hope it helps someone.


If I understand your goal, and how you currently have it implemented. You should check if you need to return first.

if ((cursorPosition.x + 30) >= message.frame.width) {
    message.text = message.text.stringByAppendingString("\n");

Then you should get the now current cursor position, and add your UIImageView there.
let size = CGSize(width: 30, height: 30);

let img = UIImage(named: change_arr[indexPath.row]);
let addImg = UIImageView(image: UIImage(named: change_arr[indexPath.row]));
addImg.frame = CGRect(origin: newCursorPosition, size: size);


then if you need to add spaces, add them now.

As stated in the previous comments using NSTextAttachment will simplify all of this, and prevent you from having to create UIViews, etc...

it would look something like this, and you don't need to check for the cursor position, because it will handle that just like it does with text.

//create your UIImage
let image = UIImage(named: change_arr[indexPath.row]);
//create and NSTextAttachment and add your image to it.
let attachment = NSTextAttachment()
attachment.image = image
//put your NSTextAttachment into and attributedString
let attString = NSAttributedString(attachment: attachment)
//add this attributed string to the current position.
textView.textStorage.insertAttributedString(attString, atIndex: textView.selectedRange.location)

Now the image is inline, and treated like text. If the user backspaces over it, it deletes just like text.