I need to create button programatically with an image for normal and highlighted state as well text. I cannot build it using Interface Builder, because I need to create butt
You've made a mistake there, you're doing
[btn setBackgroundImage:buttonImage forState:UIControlStateNormal];
instead of
[btn setImage:buttonImage forState:UIControlStateNormal];
This will work fine.
Have you tried
[btn setBackgroundImage:buttonImage forState:UIControlStateHighlighted];
It might solve your problem.
Swift 4
- if you want to display an image prefix with title
func AttributedTextwithImagePrefix(AttributeImage : UIImage , AttributedText : String , buttonBound : UIButton) -> NSMutableAttributedString
{
let fullString = NSMutableAttributedString(string: " ")
let image1Attachment = NSTextAttachment()
image1Attachment.bounds = CGRect(x: 0, y: ((buttonBound.titleLabel?.font.capHeight)! - AttributeImage.size.height).rounded() / 2, width: AttributeImage.size.width, height: AttributeImage.size.height)
image1Attachment.image = AttributeImage
let image1String = NSAttributedString(attachment: image1Attachment)
fullString.append(image1String)
fullString.append(NSAttributedString(string: " " + AttributedText))
return fullString
}
this is how you can use this :
self.btnprefix.setAttributedTitle(AttributedTextwithImagePrefix(AttributeImage: #imageLiteral(resourceName: "avtar"), AttributedText: " prefix avtar", buttonBound: self.prefix), for: .normal)
- if you want to display an image suffix with title
func AttributedTextwithImageSuffix(AttributeImage : UIImage , AttributedText : String , buttonBound : UIButton) -> NSMutableAttributedString
{
let fullString = NSMutableAttributedString(string: AttributedText + " ")
let image1Attachment = NSTextAttachment()
image1Attachment.bounds = CGRect(x: 0, y: ((buttonBound.titleLabel?.font.capHeight)! - AttributeImage.size.height).rounded() / 2, width: AttributeImage.size.width, height: AttributeImage.size.height)
image1Attachment.image = AttributeImage
let image1String = NSAttributedString(attachment: image1Attachment)
fullString.append(image1String)
fullString.append(NSAttributedString(string: ""))
return fullString
}
this is how you can use this :
self.btnsuffix.setAttributedTitle(AttributedTextwithImageSuffix(AttributeImage: #imageLiteral(resourceName: "avtar"), AttributedText: " suffix avtar", buttonBound: self.btnsuffix), for: .normal)
OUTPUT WILL BE
I think Azharhussain Shaikh's answer is not working with larger images so I've twisted it a little and converted to a Swift 4 extension to UIButton. There you go:
extension UIButton {
func setAttributedTextWithImagePrefix(image: UIImage, text: String, for state: UIControl.State) {
let fullString = NSMutableAttributedString()
if let imageString = getImageAttributedString(image: image) {
fullString.append(imageString)
}
fullString.append(NSAttributedString(string: " " + text))
self.setAttributedTitle(fullString, for: state)
}
func setAttributedTextWithImageSuffix(image: UIImage, text: String, for state: UIControl.State) {
let fullString = NSMutableAttributedString(string: text + " ")
if let imageString = getImageAttributedString(image: image) {
fullString.append(imageString)
}
self.setAttributedTitle(fullString, for: state)
}
fileprivate func getImageAttributedString(image: UIImage) -> NSAttributedString? {
let buttonHeight = self.frame.height
if let resizedImage = image.getResizedWithAspect(maxHeight: buttonHeight - 10) {
let imageAttachment = NSTextAttachment()
imageAttachment.bounds = CGRect(x: 0, y: ((self.titleLabel?.font.capHeight)! - resizedImage.size.height).rounded() / 2, width: resizedImage.size.width, height: resizedImage.size.height)
imageAttachment.image = resizedImage
let image1String = NSAttributedString(attachment: imageAttachment)
return image1String
}
return nil
}
}
and a extension to UIImage:
extension UIImage {
func getResized(size: CGSize) -> UIImage? {
if UIScreen.main.responds(to: #selector(NSDecimalNumberBehaviors.scale)) {
UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale);
} else {
UIGraphicsBeginImageContext(size);
}
self.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height));
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
func getResizedWithAspect(scaledToMaxWidth width: CGFloat? = nil, maxHeight height: CGFloat? = nil) -> UIImage? {
let oldWidth = self.size.width;
let oldHeight = self.size.height;
var scaleToWidth = oldWidth
if let width = width {
scaleToWidth = width
}
var scaleToHeight = oldHeight
if let height = height {
scaleToHeight = height
}
let scaleFactor = (oldWidth > oldHeight) ? scaleToWidth / oldWidth : scaleToHeight / oldHeight;
let newHeight = oldHeight * scaleFactor;
let newWidth = oldWidth * scaleFactor;
let newSize = CGSize(width: newWidth, height: newHeight);
return getResized(size: newSize);
}
}
UIButtons setImage sets the image above the title so you will not be able to see the text below it. So try to set image to your button with setBackgroundImage.
Objective-C:
[btn setBackgroundImage:buttonImage forState:UIControlStateNormal];
Swift:
myButton.setBackgroundImage(buttonImage, forState: .normal)
var menuButton:UIButton?
override func viewWillAppear(animated: Bool) {
menuButton = UIButton(frame: CGRectMake(0,0,30,30))
menuButton?.setBackgroundImage(UIImage(named: "menu.png"), forState: UIControlState.Normal)
}