How to embed small icon in UILabel
Asked Answered
E

21

193

I need to embed small icons ( sort of custom bullets ) to my UILabel in iOS7. How can I do this in interface designer? Or at least in code?

In Android there are leftDrawable and rightDrawable for labels, but how it is done in iOS? Sample in android :

android sample

Entwine answered 11/10, 2013 at 12:41 Comment(2)
I not familier with Android can you post some image for reference?Meador
create a small imageview and add it as subview to label's objectAgribusiness
N
316

You can do this with iOS 7's text attachments, which are part of TextKit. Some sample code:

NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = [UIImage imageNamed:@"MyIcon.png"];

NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:attachment];

NSMutableAttributedString *myString= [[NSMutableAttributedString alloc] initWithString:@"My label text"];
[myString appendAttributedString:attachmentString];

myLabel.attributedText = myString;
Neman answered 11/10, 2013 at 14:25 Comment(12)
How about iOS6? Do you have any suggestion?? ThxDoralia
@StevenJiang: You'll have to just add a UIImageView to your labelNeman
Unfortunately this places the icon after the text. Any chance that we can move this before the text because I can't find a way?!Biology
@Biology Instead of appending the image (attachment string) to your textual string, you could try that the other way around, so appending the textual string to the attachment string.Neman
Already tried this yesterday. Seems like a missed something because now it works. Thanks. Just in case for everyone who's trying to accomplish the same (since it's slightly different): NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:attachment]; NSMutableAttributedString *myString = [[NSMutableAttributedString alloc] initWithAttributedString:attachmentString]; NSAttributedString *myText = [[NSMutableAttributedString alloc] initWithString:text]; [myString appendAttributedString:myText];Biology
but image is displaying right side..... How i need to keep on specific position ...Like [image Drawable Left]Perigon
To rectify the position you can take ref from : #26106303Promise
Its adding icon to right of the text how can we make it left align?Photolysis
@TarunSeera, see reVerse's solution about changing the append order, just above in the comments. I just want to know, is it possible to add padding to the image before the text is placed?Cagle
@Chucky: You can try messing with the bounds of the image, but that may distort your image in ways you don't want to. There is no contentMode or anything like that as far as I know, so if you want that you'll have to find a different solution unfortunately.Neman
How about adding 2 images in the label. I have tried like your solution, but both images not show, only show one default image.Ox
You'd have to show some code. Probably in a separate question on SO.Neman
P
217

Here is the way to embed icon in UILabel.

Also to Align the Icon use attachment.bounds


Swift 5.1

// Create Attachment
let imageAttachment = NSTextAttachment()
imageAttachment.image = UIImage(named:"iPhoneIcon")
// Set bound to reposition
let imageOffsetY: CGFloat = -5.0
imageAttachment.bounds = CGRect(x: 0, y: imageOffsetY, width: imageAttachment.image!.size.width, height: imageAttachment.image!.size.height)
// Create string with attachment
let attachmentString = NSAttributedString(attachment: imageAttachment)
// Initialize mutable string
let completeText = NSMutableAttributedString(string: "")
// Add image to mutable string
completeText.append(attachmentString)
// Add your text to mutable string
let textAfterIcon = NSAttributedString(string: "Using attachment.bounds!")
completeText.append(textAfterIcon)
self.mobileLabel.textAlignment = .center
self.mobileLabel.attributedText = completeText

Objective-C Version

NSTextAttachment *imageAttachment = [[NSTextAttachment alloc] init];
imageAttachment.image = [UIImage imageNamed:@"iPhoneIcon"];
CGFloat imageOffsetY = -5.0;
imageAttachment.bounds = CGRectMake(0, imageOffsetY, imageAttachment.image.size.width, imageAttachment.image.size.height);
NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:imageAttachment];
NSMutableAttributedString *completeText = [[NSMutableAttributedString alloc] initWithString:@""];
[completeText appendAttributedString:attachmentString];
NSAttributedString *textAfterIcon = [[NSAttributedString alloc] initWithString:@"Using attachment.bounds!"];
[completeText appendAttributedString:textAfterIcon];
self.mobileLabel.textAlignment = NSTextAlignmentRight;
self.mobileLabel.attributedText = completeText;

enter image description here

enter image description here

Photolysis answered 5/3, 2016 at 8:14 Comment(7)
Vote up for attachment.boundsCeraceous
Great call on using attachment.bounds. Thats exactly what I was looking for.Peterson
In fact, the imageOffsetY can be calculated instead of using a fixed value of -5.0. let imageOffsetY:CGFloat = -(imageAttachment.image!.size.height - self.mobileLabel.font.pointSize) / 2.0;Luciferin
Note: it slow down compile timeJook
I can do it on storyboard?Fiscus
How could we increase the horizontal spacing between icon and text. I used completeText.addAttribute(NSAttributedString.Key.kern, value: 12, range: NSRange(location: 0, length: 1)) but it seems not worked.Carborundum
It seems to be broken with Xcode 13 RC. The image is cut, the label height bounds does not increase with the image height (it worked great with Xcode 12.X)Vernon
D
66

Swift 4.2:

let attachment = NSTextAttachment()        
attachment.image = UIImage(named: "yourIcon.png")
let attachmentString = NSAttributedString(attachment: attachment)
let myString = NSMutableAttributedString(string: price)
myString.append(attachmentString)
label.attributedText = myString
Deepfry answered 9/2, 2015 at 15:49 Comment(0)
M
25

Swift 3 version

let attachment = NSTextAttachment()
attachment.image = UIImage(named: "plus")
attachment.bounds = CGRect(x: 0, y: 0, width: 10, height: 10)
let attachmentStr = NSAttributedString(attachment: attachment)
let myString = NSMutableAttributedString(string: "")
myString.append(attachmentStr)
let myString1 = NSMutableAttributedString(string: "My label text")
myString.append(myString1)
lbl.attributedText = myString

UILabel Extension

extension UILabel {

    func set(text:String, leftIcon: UIImage? = nil, rightIcon: UIImage? = nil) {

        let leftAttachment = NSTextAttachment()
        leftAttachment.image = leftIcon
        leftAttachment.bounds = CGRect(x: 0, y: -2.5, width: 20, height: 20)
        if let leftIcon = leftIcon {
            leftAttachment.bounds = CGRect(x: 0, y: -2.5, width: leftIcon.size.width, height: leftIcon.size.height)
        }
        let leftAttachmentStr = NSAttributedString(attachment: leftAttachment)

        let myString = NSMutableAttributedString(string: "")

        let rightAttachment = NSTextAttachment()
        rightAttachment.image = rightIcon
        rightAttachment.bounds = CGRect(x: 0, y: -5, width: 20, height: 20)
        let rightAttachmentStr = NSAttributedString(attachment: rightAttachment)


        if semanticContentAttribute == .forceRightToLeft {
            if rightIcon != nil {
                myString.append(rightAttachmentStr)
                myString.append(NSAttributedString(string: " "))
            }
            myString.append(NSAttributedString(string: text))
            if leftIcon != nil {
                myString.append(NSAttributedString(string: " "))
                myString.append(leftAttachmentStr)
            }
        } else {
            if leftIcon != nil {
                myString.append(leftAttachmentStr)
                myString.append(NSAttributedString(string: " "))
            }
            myString.append(NSAttributedString(string: text))
            if rightIcon != nil {
                myString.append(NSAttributedString(string: " "))
                myString.append(rightAttachmentStr)
            }
        }
        attributedText = myString
    }
}
Melindamelinde answered 10/3, 2017 at 14:54 Comment(0)
B
23

Your reference image looks like a button. Try (can also be done in Interface Builder):

enter image description here

UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(50, 50, 100, 44)];
[button setImage:[UIImage imageNamed:@"img"] forState:UIControlStateNormal];
[button setImageEdgeInsets:UIEdgeInsetsMake(0, -30, 0, 0)];
[button setTitle:@"Abc" forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor yellowColor]];
[view addSubview:button];
Brogue answered 11/10, 2013 at 13:8 Comment(2)
Well explained, I like the fact you took the time to provide a ref. It helped me a lot! ThanksDar
This helped get my trophy icon into a button. Thanks a lot!Withdrawn
A
16

I've made an implementation of this feature in swift here: https://github.com/anatoliyv/SMIconLabel

Code is as simple as it's possible:

var labelLeft = SMIconLabel(frame: CGRectMake(10, 10, view.frame.size.width - 20, 20))
labelLeft.text = "Icon on the left, text on the left"

// Here is the magic
labelLeft.icon = UIImage(named: "Bell") // Set icon image
labelLeft.iconPadding = 5               // Set padding between icon and label
labelLeft.numberOfLines = 0             // Required
labelLeft.iconPosition = SMIconLabelPosition.Left // Icon position
view.addSubview(labelLeft)

Here is how it looks:

SMIconLabel image

Afresh answered 29/6, 2015 at 9:30 Comment(0)
H
15

Swift 5 Easy Way Just CopyPaste and change what you want

let fullString = NSMutableAttributedString(string:"To start messaging contacts who have Talklo, tap ")

 // create our NSTextAttachment
let image1Attachment = NSTextAttachment() 
image1Attachment.image = UIImage(named: "chatEmoji")
image1Attachment.bounds = CGRect(x: 0, y: -8, width: 25, height: 25)

// wrap the attachment in its own attributed string so we can append it
let image1String = NSAttributedString(attachment: image1Attachment)

 // add the NSTextAttachment wrapper to our full string, then add some more text.

 fullString.append(image1String)
 fullString.append(NSAttributedString(string:" at the right bottom of your screen"))

 // draw the result in a label
 self.lblsearching.attributedText = fullString

enter image description here

Heyday answered 24/12, 2019 at 11:53 Comment(6)
From 2021, what happened to your screen;)Carborundum
its my girlFriend Gift, she left me but how can i trash the gift?? :-(Heyday
Sad story. I think you should keep it.Carborundum
never thought stack overflow would give me depression in this wayAssurgent
@ShakeelAhmed I'm from the future, are you okay now? Still single or married?Caitlin
@TàTruhoada Single ;-( look someone for meHeyday
E
14

Swift 4 UIlabel Extension to add Image to Label with reference to above answers

extension UILabel {
  func set(image: UIImage, with text: String) {
    let attachment = NSTextAttachment()
    attachment.image = image
    attachment.bounds = CGRect(x: 0, y: 0, width: 10, height: 10)
    let attachmentStr = NSAttributedString(attachment: attachment)

    let mutableAttributedString = NSMutableAttributedString()
    mutableAttributedString.append(attachmentStr)

    let textString = NSAttributedString(string: text, attributes: [.font: self.font])
    mutableAttributedString.append(textString)

    self.attributedText = mutableAttributedString
  }
}
Epistrophe answered 5/3, 2018 at 8:3 Comment(3)
NSAttributedString(string: " " + text, attributes: [.font: self.font])Syneresis
@grizzly is that for creating space between icon and text?Epistrophe
yes. is another way for space between icon and text?Syneresis
D
12

In Swift 5, By using UILabel extensions to embed icon in leading as well as trailing side of the text as follows:-

extension UILabel {
    
    func addTrailing(image: UIImage, text:String) {
        let attachment = NSTextAttachment()
        attachment.image = image

        let attachmentString = NSAttributedString(attachment: attachment)
        let string = NSMutableAttributedString(string: text, attributes: [:])

        string.append(attachmentString)
        self.attributedText = string
    }
    
    func addLeading(image: UIImage, text:String) {
        let attachment = NSTextAttachment()
        attachment.image = image

        let attachmentString = NSAttributedString(attachment: attachment)
        let mutableAttributedString = NSMutableAttributedString()
        mutableAttributedString.append(attachmentString)
        
        let string = NSMutableAttributedString(string: text, attributes: [:])
        mutableAttributedString.append(string)
        self.attributedText = mutableAttributedString
    }
}

To use above mentioned code in your desired label as:-

Image in right of text then:-

statusLabel.addTrailing(image: UIImage(named: "rightTick") ?? UIImage(), text: " Verified ")

Image in left of text then:-

statusLabel.addLeading(image: UIImage(named: "rightTick") ?? UIImage(), text: " Verified ")

Output:-

enter image description here

enter image description here

Drowse answered 25/11, 2020 at 10:46 Comment(0)
M
5

try this way...

  self.lbl.text=@"Drawble Left";
    UIImageView *img=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 20, 20)];
    img.image=[UIImage imageNamed:@"Star.png"];
    [self.lbl addSubview:img];
Meador answered 11/10, 2013 at 13:2 Comment(2)
Is this helpful to you?Meador
this approach misses text offset for image (text lies behind image)Pneumectomy
G
3

Swift 2.0 version:

//Get image and set it's size
let image = UIImage(named: "imageNameWithHeart")
let newSize = CGSize(width: 10, height: 10)

//Resize image
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image?.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
let imageResized = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

//Create attachment text with image
var attachment = NSTextAttachment()
attachment.image = imageResized
var attachmentString = NSAttributedString(attachment: attachment)
var myString = NSMutableAttributedString(string: "I love swift ")
myString.appendAttributedString(attachmentString)
myLabel.attributedText = myString
Greenling answered 14/1, 2016 at 10:57 Comment(0)
T
3

Swift 5+

If you want to keep the ratio of the image and the image always centered with the text, then, this is my solution:

extension UILabel {
    var mutableAttributedString: NSMutableAttributedString? {
        let attributedString: NSMutableAttributedString
        if let labelattributedText = self.attributedText {
            attributedString = NSMutableAttributedString(attributedString: labelattributedText)
        } else {
            guard let labelText = self.text else { return nil }
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.alignment = self.textAlignment
            attributedString = NSMutableAttributedString(string: labelText)
            attributedString.addAttribute(NSAttributedString.Key.paragraphStyle,
                                          value: paragraphStyle,
                                          range: NSRange(location: 0, length: attributedString.length))
        }
        return attributedString
    }

    func addImage(_ image: UIImage, toEndWith height: CGFloat) {
        let fullAttributedString = mutableAttributedString
        let imageAttachment = NSTextAttachment()
        imageAttachment.image = image

        let yImage = (font.capHeight - height).rounded() / 2
        let ratio = image.size.width / image.size.height
        imageAttachment.bounds = CGRect(x: 0, y: yImage, width: ratio * height, height: height)
        
        let imageString = NSAttributedString(attachment: imageAttachment)
        fullAttributedString?.append(imageString)
        attributedText = fullAttributedString
    }
    
    func addImage(_ image: UIImage, toStartWith height: CGFloat) {
        let imageAttachment = NSTextAttachment()
        imageAttachment.image = image

        let yImage = (font.capHeight - height).rounded() / 2
        let ratio = image.size.width / image.size.height
        imageAttachment.bounds = CGRect(x: 0, y: yImage, width: ratio * height, height: height)
        
        let fullAttributed = NSMutableAttributedString(attachment: imageAttachment)
        if let rawAttributed = mutableAttributedString {
            fullAttributed.append(rawAttributed)
        }
        attributedText = fullAttributed
    }
}

And this is how to use the above extension:

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
label.font = .systemFont(ofSize: 20)
let image = UIImage(systemName: "square.and.pencil")!
label.text = "Hi, "
label.addImage(image, toEndWith: 10)

These are some examples:

enter image description here

enter image description here

enter image description here

Using with an attributed string:

let myString = "Hi, "
let myAttribute: [NSAttributedString.Key: UIColor] = [.foregroundColor: .blue]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute)
label.attributedText = myAttrString
label.addImage(image, toEndWith: 15)

enter image description here

Telegram answered 21/8, 2022 at 0:44 Comment(0)
S
2

Try dragging a UIView onto the screen in IB. From there you can drag a UIImageView and UILabel into the view you just created. Set the image of the UIImageView in the properties inspector as the custom bullet image (which you will have to add to your project by dragging it into the navigation pane) and you can write some text in the label.

Shriver answered 12/10, 2013 at 11:6 Comment(0)
L
2

You can extent UILabe pass the flag for the image add-in Leading or Trailing also set imageBounds if needed.

Swift 5+

extension UILabel {
    func add(image: UIImage, text: String, isLeading: Bool = true, imageBounds: CGRect = CGRect(x: 0, y: 0, width: 16, height: 12)) {
        let imageAttachment = NSTextAttachment()
        imageAttachment.bounds = imageBounds
        
        imageAttachment.image = image
        
        let attachmentString = NSAttributedString(attachment: imageAttachment)
        let string = NSMutableAttributedString(string: text)
        
        let mutableAttributedString = NSMutableAttributedString()
        
        if isLeading {
            mutableAttributedString.append(attachmentString)
            mutableAttributedString.append(string)
            attributedText = mutableAttributedString
        } else {
            string.append(attachmentString)
            attributedText = string
        }
    }
    }
Latonia answered 16/7, 2021 at 14:8 Comment(0)
S
2

For somebody who wants to have an icon on the right end of their label, not necessarily immediately after the text, you can use this technique based on the idea in this answer: https://mcmap.net/q/134259/-how-to-embed-small-icon-in-uilabel (Note there are some constants here you will probably want to adjust, but the general idea should be clear). This will not work if your label is being sized using its implicit size, only if you have some other constraint on the width that you are confident will leave room for your icon.

    let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
    imgView.image = UIImage(named: "arrow")
    myLabel.addSubview(imgView)
    imgView.translatesAutoresizingMaskIntoConstraints = false
    imgView.centerYAnchor.constraint(equalTo: myLabel.centerYAnchor, constant: 0).isActive = true
    imgView.rightAnchor.constraint(equalTo: myLabel.rightAnchor, constant: -20).isActive = true
Synopsis answered 24/11, 2021 at 13:57 Comment(0)
A
1

you have to make a custom object where you used a UIView and inside you put a UIImageView and a UILabel

Adolescent answered 11/10, 2013 at 13:2 Comment(0)
P
1

You could use a UITextField with the leftView property and then set the enabled property to NO

Or use a UIButton and setImage:forControlState

Pollster answered 11/10, 2013 at 14:13 Comment(0)
P
1
 func atributedLabel(str: String, img: UIImage)->NSMutableAttributedString
{   let iconsSize = CGRect(x: 0, y: -2, width: 16, height: 16)
    let attributedString = NSMutableAttributedString()
    let attachment = NSTextAttachment()
    attachment.image = img
    attachment.bounds = iconsSize
    attributedString.append(NSAttributedString(attachment: attachment))
    attributedString.append(NSAttributedString(string: str))

    return attributedString
} 

You can use this function to add images or small icons to the label

Psycholinguistics answered 23/2, 2018 at 11:0 Comment(3)
Call this in viewdidload()Psycholinguistics
let emojisCollection = [UIImage(named: "ic_place"), UIImage(named: "ic_group"), UIImage(named: "ic_analytics")] lbl1.attributedText = atributedLabel(str: " Howath, Dublin", img: emojisCollection[0]!) lbl2.attributedText = atributedLabel(str: " Difficulty: 18+", img: emojisCollection[2]!) lbl3.attributedText = atributedLabel(str: " Maximum group size: 10", img: emojisCollection[1]!)Psycholinguistics
you can edit you original answer to include those comments above.Rh
S
0

In Swift 2.0,

My solution to the problem is a combination of a couple of answers on this question. The problem I faced in @Phil's answer was that I couldn't change the position of the icon, and it always appeared in right the corner. And the one answer from @anatoliy_v, I couldn't resize the icon size I want to append to the string.

To make it work for me, I first did a pod 'SMIconLabel' and then created this function:

func drawTextWithIcon(labelName: SMIconLabel, imageName: String, labelText: String!,  width: Int, height: Int) {

        let newSize = CGSize(width: width, height: height)
        let image = UIImage(named: imageName)
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
        image?.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
        let imageResized = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        labelName.text = " \(labelText)"
        labelName.icon = imageResized
        labelName.iconPosition = .Left
    }

This solution will not only help you place the image but will also allow you to make necessary changes to the icon size and other attributes.

Thank You.

Saunderson answered 25/2, 2016 at 9:9 Comment(0)
S
0

Swift 3 UILabel extention

Tip: If you need some space between the image and the text just use a space or two before the labelText.

extension UILabel {
    func addIconToLabel(imageName: String, labelText: String, bounds_x: Double, bounds_y: Double, boundsWidth: Double, boundsHeight: Double) {
        let attachment = NSTextAttachment()
        attachment.image = UIImage(named: imageName)
        attachment.bounds = CGRect(x: bounds_x, y: bounds_y, width: boundsWidth, height: boundsHeight)
        let attachmentStr = NSAttributedString(attachment: attachment)
        let string = NSMutableAttributedString(string: "")
        string.append(attachmentStr)
        let string2 = NSMutableAttributedString(string: labelText)
        string.append(string2)
        self.attributedText = string
    }
}
Sp answered 4/7, 2017 at 13:33 Comment(1)
I used this and it worked perfectly. The other ones above actually flipped the image to the end of the string.Runaway
G
0

If you don't absolutely need a label (and there may be some situations where you do), you can use a view hierarchy with constraints to create a UIView that can be placed where a label would go. And, of course the image and label text of the composite view can be updated dynamically.

func configureTitleLabelWithIcon(text: String, parent: UIView) {

    let iconAndLabel = UIView()
    let label = UILabel()
    let icon  = UIImageView(image:UIImage(systemName: "globe"))

    label.text = text
    label.textColor = UIColor.secondaryLabel
    
    label.translatesAutoresizingMaskIntoConstraints = false
    ico .translatesAutoresizingMaskIntoConstraints = false
    iconAndLabel.translatesAutoresizingMaskIntoConstraints = false

    iconAndLabel.addSubview(icon)
    iconAndLabel.addSubview(label)

    icon.widthAnchor.constraint(  equalToConstant: 14).isActive = true
    icon.heightAnchor.constraint( equalToConstant: 14).isActive = true

    iconAndLabel.widthAnchor.constraint(  equalToConstant: 200).isActive = true
    iconAndLabel.heightAnchor.constraint( equalToConstant: 22).isActive = true

    icon.leadingAnchor.constraint(equalTo:   iconAndLabel.leadingAnchor).isActive = true
    icon.trailingAnchor.constraint(equalTo:  label.leadingAnchor, constant: -7).isActive = true
    label.trailingAnchor.constraint(equalTo: iconAndLabel.trailingAnchor).isActive = true
    icon.centerYAnchor.constraint(equalTo:   iconAndLabel.centerYAnchor).isActive = true
    view.addSubview(iconAndLabel)

    label.centerXAnchor.constraint(equalTo: parent, constant: 10).isActive = true
    label.bottomAnchor.constraint(equalTo:  parent, constant: -75).isActive = true
}
Growl answered 2/5, 2022 at 6:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.