Reputation: 811
I've seen posts regarding right alignment but I can't get left-alignment to work. I want the button to take up the width of the screen, with the image on the left and the title/text in the center.
This does not work (at least reliably):
button.titleLabel.textAlignment = UITextAlignmentCenter;
[button setImageEdgeInsets:UIEdgeInsetsMake(0, -60.0, 0, 0)];
button.frame = CGRectMake((self.view.frame.size.width - w ) / 2, self.view.frame.size.height - 140.0, self.view.frame.size.width - 10.0, 40.0);
Upvotes: 79
Views: 108335
Reputation: 34
SWIFT 5+
Maybe the easiest and best looking variant is to use UIButton.Configuration
private func bottomButtonsConfiguration() -> UIButton.Configuration {
var config: UIButton.Configuration = .filled()
config.background.backgroundColor = Asset.Colors.cellsBackground.color
config.baseForegroundColor = Asset.Colors.textColorOnLight.color
config.cornerStyle = .small
config.imagePadding = 14
config.imagePlacement = .top
config.imageColorTransformer = UIConfigurationColorTransformer { _ in
return Asset.Colors.primaryColor.color
}
config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { attribute in
var muttableAttribute = attribute
muttableAttribute.font = self.theme.font(style: .medium, size: 16)
return muttableAttribute
}
return config
}
Solution for your problem is config.imagePlacement = .top
Upvotes: -1
Reputation: 11
@trishcode answer worked for me. I am just using it with an extension of the UIButton.
Here is the code:
extension UIButton {
func centerImageLeft(padding: CGFloat = 30.0){
let buttonWidth = self.frame.width
let textWidth = self.titleLabel?.intrinsicContentSize.width ?? 0
let imageViewWidth = self.imageView?.frame.size.width ?? 0
let offsetToLeftButtonEdge = buttonWidth - textWidth - imageViewWidth
let offset = offsetToLeftButtonEdge - padding
self.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: 0, bottom: 0.0, right: offset)
}
}
You can then call it like this in the viewDidAppear Method:
button.centerImageLeft()
Upvotes: 1
Reputation: 3549
This works for me with varying button text sizes.
The key for an accurate button text width is to get the intrinsicContentSize. Since I'm using auto layout for the button width, I had to run this code from viewDidAppear instead of viewDidLoad so the button would be drawn already and, therefore, the button frame size would be accurate.
private func calculateAccountButtonImageViewOffset(button: UIButton, padding: CGFloat = 30.0) -> CGFloat {
let buttonWidth = button.frame.width
let textWidth = button.titleLabel?.intrinsicContentSize.width ?? 0
let imageViewWidth = button.imageView?.frame.size.width ?? 0
let offsetToLeftButtonEdge = buttonWidth - textWidth - imageViewWidth
return offsetToLeftButtonEdge - padding
}
Usage:
let imageViewOffset = calculateAccountButtonImageViewOffset(button: button)
button.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: 0, bottom: 0.0, right: imageViewOffset)
The button title can be offset as desired with Title Insets on IB:
Upvotes: 0
Reputation: 7932
For Swift 4.0, here's an extension that works-
extension UIButton {
func leftImage(image: UIImage, renderMode: UIImage.RenderingMode) {
self.setImage(image.withRenderingMode(renderMode), for: .normal)
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0)
self.titleEdgeInsets.left = (self.frame.width/2) - (self.titleLabel?.frame.width ?? 0)
self.contentHorizontalAlignment = .left
self.imageView?.contentMode = .scaleAspectFit
}
func rightImage(image: UIImage, renderMode: UIImageRenderingMode){
self.setImage(image.withRenderingMode(renderMode), for: .normal)
self.imageEdgeInsets = UIEdgeInsets(top: 0, left:image.size.width / 2, bottom: 0, right: 0)
self.contentHorizontalAlignment = .right
self.imageView?.contentMode = .scaleAspectFit
}
}
Usage:
myButton.rightImage(image: UIImage(named: "image_name")!, renderMode: .alwaysOriginal)
myButton.leftImage(image: UIImage(named: "image_name")!, renderMode: .alwaysOriginal)
renderMode
can be .alwaysTemplate
or .alwaysOriginal
. Also, myButton
should be a custom
type UIButton
.
This extension's leftImage
and rightImage
can also be used in UIButton
in UIBarButtonItem
for UINavigationBar
(Note: as of iOS 11, the navigation bar follows autolayout so you will need to add width/height constraints to the UIBarButtonItem
). For usage on Navigation Bar, make sure you follow the Apple recommended @2x and @3x image sizes (i.e. 50x50, 75x75) and to have better accessibility on iPhone 6, 7 , 8, 6s, 7s, 8s, the Plus variants and iPhone x the width and height of the UIBarButton
could be height - 25 and width - 55 (or whatever your app requires, these numbers are some basic numbers that should work for most cases).
UPDATE: In Swift 4.2, UIImageRenderingMode
has been renamed to UIImage.RenderingMode
extension UIButton {
func leftImage(image: UIImage, renderMode: UIImage.RenderingMode) {
self.setImage(image.withRenderingMode(renderMode), for: .normal)
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: image.size.width / 2)
self.contentHorizontalAlignment = .left
self.imageView?.contentMode = .scaleAspectFit
}
func rightImage(image: UIImage, renderMode: UIImage.RenderingMode){
self.setImage(image.withRenderingMode(renderMode), for: .normal)
self.imageEdgeInsets = UIEdgeInsets(top: 0, left:image.size.width / 2, bottom: 0, right: 0)
self.contentHorizontalAlignment = .right
self.imageView?.contentMode = .scaleAspectFit
}
}
Upvotes: 19
Reputation: 71
You may forget about UIEdgeInsets and simply override frames in layoutSubviews() within your UIButton subclass.
To center the titleLable, simply add horizontal offset to the titleLabel frame by the difference between super.bounds.midX and titleLabel.frame.midX
override func layoutSubviews() {
super.layoutSubviews()
if let label = titleLabel {
label.frame = label.frame.offsetBy(dx: super.bounds.midX -
label.frame.midX , dy: 0)
}
// Available space to the left of the titleLabel is simply:
let leftAvailableWidth = label.frame.minX
imageView?.frame = CGRect(x: 0, y: 0, width: <Some width smaller than leftAvailableWidth>, height: super.bound.height)
}
Upvotes: 1
Reputation: 739
this code makes your button image to align left, and title label moves to center of button. b is button :)
b.contentHorizontalAlignment = .Left
let left = (b.frameWidth() - b.titleLabel!.frameWidth()) / 2 - CGRectGetMaxX(b.imageView!.frame)
b.titleEdgeInsets = UIEdgeInsetsMake(0, left, 0, 0)
Upvotes: 1
Reputation: 5410
Swift version:
var button = UIButton()
newGameButton.setTitle("Новая игра", for: .normal)
newGameButton.setImage(UIImage(named: "energi"), for: .normal)
newGameButton.backgroundColor = .blue
newGameButton.imageEdgeInsets.left = -50
Upvotes: 2
Reputation: 168
My SWIFT 5.2 solution.
You have to subclass UIButton class. No need to change the content horizontal alignment like others did in other answers, keep it to "center" (.center). The title will be automatically centered, while the override of imageRect() will do the trick for the image.
The first thing you have to do is to assign CustomButton class to your button in storyboard's Identity Inspector section. Then, you can switch "alignImageToLeft" to ON or OFF on Attribute Inspector's section (default will be OFF).
class CustomButton : UIButton {
@IBInspectable var alignImageToLeft : Bool = false
override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
if(alignImageToLeft){
let imageRect = super.imageRect(forContentRect: contentRect)
let offset = contentRect.minX - imageRect.minX
return imageRect.offsetBy(dx: offset, dy: 0.0)
}
return super.imageRect(forContentRect: contentRect)
}
}
Upvotes: 2
Reputation: 269
I've tried almost every solution above and none of them worked as I expected (I had two buttons each with different tittle and with different image width). So I have written my own extension for UIButton, which works flawlessly with different image widths as well as with different titles.
extension UIButton {
func moveImageLeftTextCenter(imagePadding: CGFloat = 30.0, titlePadding: CGFloat = 0.0, minImageTitleDistance: CGFloat = 10.0){
guard let imageViewWidth = imageView?.frame.width else{return}
guard let titleLabelWidth = titleLabel?.intrinsicContentSize.width else{return}
contentHorizontalAlignment = .left
let imageLeftInset = imagePadding - imageViewWidth / 2
var titleLeftInset = (bounds.width - titleLabelWidth) / 2 - imageViewWidth + titlePadding
if titleLeftInset - imageLeftInset < minImageTitleDistance{
titleLeftInset = imageLeftInset + minImageTitleDistance
}
imageEdgeInsets = UIEdgeInsets(top: 0.0, left: imageLeftInset, bottom: 0.0, right: 0.0)
titleEdgeInsets = UIEdgeInsets(top: 0.0, left: titleLeftInset, bottom: 0.0, right: 0.0)
}
}
Usage: myButton.moveImageLeftTextCenter()
Upvotes: 12
Reputation: 3219
Swift 5: You can achieve this by using custom class of UIButton.
class CustomButton: UIButton {
var imageV = UIImageView()
var titleV = UILabel()
override func awakeFromNib() {
self.imageView?.isHidden = true
self.titleLabel?.isHidden = true
imageV.frame = CGRect(x: 0, y: 0, width: 40, height: self.bounds.height)
imageV.contentMode = .scaleAspectFit
titleV.frame = CGRect(x: 40, y: 0, width: self.bounds.width - 40, height: self.bounds.height)
titleV.font = self.titleLabel?.font
titleV.textAlignment = .center
self.addSubview(imageV)
self.addSubview(titleV)
imageV.image = self.imageView?.image; titleV.text = self.titleLabel?.text
imageV.translatesAutoresizingMaskIntoConstraints = false
imageV.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
imageV.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
imageV.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
imageV.trailingAnchor.constraint(equalTo: titleV.leadingAnchor, constant: 0).isActive = true
imageV.widthAnchor.constraint(equalToConstant: 40).isActive = true
titleV.translatesAutoresizingMaskIntoConstraints = false
titleV.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
titleV.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
titleV.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
}
}
And later you can set image and text like this.
button.imageV.image = myImage
button.titleV.text = myText
Result
Upvotes: 0
Reputation: 1251
In my end, I did this using UIEdgeInsetsMake which the left corner is calculated to make it to the center. I am not sure if there's something really you can make the text at aligned at the center but this works for me. Make sure that you set your left corner to your desired position by calculating the width. e.g. UIEdgeInsetsMake(0.0f, 42.0f, 0.0f, 0.0f)
UIButton *scanBarCodeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
scanBarCodeButton.frame = CGRectMake(center, 10.0f, fieldWidth, 40.0f);
[scanBarCodeButton setImage:[UIImage imageNamed:@"BarCodeIcon.png"] forState:UIControlStateNormal];
[scanBarCodeButton setTitle:@"Scan the Barcode" forState:UIControlStateNormal];
scanBarCodeButton.titleEdgeInsets = UIEdgeInsetsMake(0.0f, 42.0f, 0.0f, 0.0f);
[scanBarCodeButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[scanBarCodeButton addTarget:self action:@selector(scanBarCode:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:scanBarCodeButton];
The output looks like,
In Swift:
var scanBarCodeButton: UIButton = UIButton(type: .roundedRect)
scanBarCodeButton.frame = CGRectMake(center, 10.0, fieldWidth, 40.0)
scanBarCodeButton.setImage(UIImage(named: "BarCodeIcon.png"), for: UIControlStateNormal)
scanBarCodeButton.setTitle("Scan the Barcode", for: UIControlStateNormal)
scanBarCodeButton.titleEdgeInsets = UIEdgeInsetsMake(0.0, 42.0, 0.0, 0.0)
scanBarCodeButton.contentHorizontalAlignment = .left
scanBarCodeButton.addTarget(self, action: "scanBarCode:", for: UIControlEventTouchUpInside)
self.view.addSubview(scanBarCodeButton)
Upvotes: 52
Reputation: 514
Tried most of the answers with no luck. I was getting a blue image most of the time, or the title was not center. Used code from a few of the answers and wrote this extension, works like a charm.
Swift 4.2:
import UIKit
extension UIButton {
func moveImageLeftTextCenter(image : UIImage, imagePadding: CGFloat, renderingMode: UIImage.RenderingMode){
self.setImage(image.withRenderingMode(renderingMode), for: .normal)
guard let imageViewWidth = self.imageView?.frame.width else{return}
guard let titleLabelWidth = self.titleLabel?.intrinsicContentSize.width else{return}
self.contentHorizontalAlignment = .left
let imageLeft = imagePadding - imageViewWidth / 2
let titleLeft = (bounds.width - titleLabelWidth) / 2 - imageViewWidth
imageEdgeInsets = UIEdgeInsets(top: 0.0, left: imageLeft, bottom: 0.0, right: 0.0)
titleEdgeInsets = UIEdgeInsets(top: 0.0, left: titleLeft , bottom: 0.0, right: 0.0)
}
}
Hope it helps for some!
Upvotes: 7
Reputation: 1485
Following extension works for me in Swift 4.2
func leftImage(image: UIImage, padding: CGFloat, renderMode: UIImage.RenderingMode) {
self.setImage(image.withRenderingMode(renderMode), for: .normal)
contentHorizontalAlignment = .left
let availableSpace = bounds.inset(by: contentEdgeInsets)
let availableWidth = availableSpace.width - imageEdgeInsets.right - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
titleEdgeInsets = UIEdgeInsets(top: 0, left: availableWidth / 2, bottom: 0, right: 0)
imageEdgeInsets = UIEdgeInsets(top: 0, left: padding, bottom: 0, right: 0)
}
func rightImage(image: UIImage, padding: CGFloat, renderMode: UIImage.RenderingMode){
self.setImage(image.withRenderingMode(renderMode), for: .normal)
semanticContentAttribute = .forceRightToLeft
contentHorizontalAlignment = .right
let availableSpace = bounds.inset(by: contentEdgeInsets)
let availableWidth = availableSpace.width - imageEdgeInsets.left - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: availableWidth / 2)
imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: padding)
}
Upvotes: 2
Reputation: 200
This solution can be applied using an extension. No need of subclassing.
Warning: this must be called every time the text/image is updated.
let width = frame.width
guard let imageWidth = imageView?.frame.width, let labelWidth = titleLabel?.frame.width else {
return
}
titleEdgeInsets = UIEdgeInsets(top: 0, left: (width - labelWidth)/2.0 - imageWidth, bottom: 0, right: 0)
Upvotes: 1
Reputation: 19249
This solution works with Swift 3 and respects original content and image edge insets while keeping the title label always centered in the available space, which makes much easier adjusting margins.
It overrides titleRect(forContentRect:)
method and returns the correct frame:
@IBDesignable
class LeftAlignedIconButton: UIButton {
override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
let titleRect = super.titleRect(forContentRect: contentRect)
let imageSize = currentImage?.size ?? .zero
let availableWidth = contentRect.width - imageEdgeInsets.right - imageSize.width - titleRect.width
return titleRect.offsetBy(dx: round(availableWidth / 2), dy: 0)
}
}
The following insets:
Would result in this:
Deprecated previous answer
This works in most scenarios, but some layouts cause layoutSubviews
to recursively call itself in an endless loop, so use with caution.
@IBDesignable
class LeftAlignedIconButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
contentHorizontalAlignment = .left
let availableSpace = UIEdgeInsetsInsetRect(bounds, contentEdgeInsets)
let availableWidth = availableSpace.width - imageEdgeInsets.right - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
titleEdgeInsets = UIEdgeInsets(top: 0, left: availableWidth / 2, bottom: 0, right: 0)
}
}
This code would do the same but aligning the icon to the right edge:
@IBDesignable
class RightAlignedIconButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
semanticContentAttribute = .forceRightToLeft
contentHorizontalAlignment = .right
let availableSpace = UIEdgeInsetsInsetRect(bounds, contentEdgeInsets)
let availableWidth = availableSpace.width - imageEdgeInsets.left - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: availableWidth / 2)
}
}
The right allignment version uses semanticContentAttribute
so it requires iOS 9+.
Upvotes: 76
Reputation: 2414
I wrote an UIButton extension.
extension UIButton {
/// Add image on left view
func leftImage(image: UIImage) {
self.setImage(image, for: .normal)
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: image.size.width)
}
}
And you could use like this :
yourButton.leftImage(image: yourImage)
Voila !
Upvotes: 9
Reputation: 41
I know this answer is kinda late. But I have a very simple solution for folks who want to add an image, using UIImageView, in the left side of an UIButton with centered text. All programmatically
class RandomVC: UIViewController{
var imageDemo: UIImageView = {
let img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.image = UIImage(named: "someImgFromAssets")
return img
}()
lazy var someButton: UIButton = { //lazy var: so button can have access to self class
let button = UIButton(type: .system)
button.setTitle("This is your title", for: UIControlState.normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(UIColor.white, for: UIControlState.normal)
button.addTarget(self, action: #selector(handleButtonClick), for: .touchUpInside) //make sure you write function "handleButtonClick" inside your class
button.titleLabel?.textAlignment = .center
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubView(someButton)
someButton.addSubview(imageDemo)
imageDemo.centerYAnchor.constraint(equalTo: someButton.centerYAnchor).isActive = true
imageDemo.leftAnchor.constraint(equalTo: someButton.leftAnchor, constant: 10).isActive = true
imageDemo.heightAnchor.constraint(equalToConstant: 25).isActive = true
imageDemo.widthAnchor.constraint(equalToConstant: 25).isActive = true
}
}
Upvotes: 2
Reputation: 453
[self.button setImage:[UIImage imageNamed:@"image.png"] forState:UIControlStateNormal];
[self.button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, self.button.center.x/2 , 0.0, 0.0)];
[self.button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
Let me know if it is not working.
Upvotes: 9
Reputation: 2980
I wrote an UIButton extension in swift -
extension UIButton {
func setLeftImage(imageName:String, padding:CGFloat) {
//Set left image
let image = UIImage(named: imageName)
self.setImage(image, forState: .Normal)
//Calculate and set image inset to keep it left aligned
let imageWidth = image?.size.width
let textWidth = self.titleLabel?.intrinsicContentSize().width
let buttonWidth = CGRectGetWidth(self.bounds)
let padding:CGFloat = 30.0
let rightInset = buttonWidth - imageWidth! - textWidth! - padding
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: rightInset)
}
}
I would style my button text any way i want, keep it in center alignment. Then I would call this method on my button like -
myButton.setLeftImage("image_name", 30.0)
This would result in my image to be left aligned with some padding from the left border.
Upvotes: 3
Reputation: 217
You can use below code to Left-align image on UIButton :-
Step 1:
//create your UIButton
UIButton *post_bNeeds_BTN= [UIButton buttonWithType:UIButtonTypeRoundedRect];
post_bNeeds_BTN.frame= CGRectMake(160 ,5 ,150 ,40);
[post_bNeeds_BTN addTarget:self action:@selector(post_Buying_Needs_BTN_Pressed:) forControlEvents:UIControlEventTouchUpInside];
[post_bNeeds_BTN setBackgroundColor:[UIColor colorWithRed:243/255.0 green:131/255.0 blue:26/255.0 alpha:1.0f]];//230
[self.view addSubview:post_bNeeds_BTN];
post_bNeeds_BTN.autoresizingMask= UIViewAutoresizingFlexibleWidth;
Step 2:
//Add UIImageView on right side the button
UIImageView *bNeedsIVw= [[UIImageView alloc] initWithFrame:CGRectMake(5,5,30,30)];
bNeedsIVw.image= [UIImage imageNamed:@"postRequir_30.png"];
bNeedsIVw.image= [bNeedsIVw.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
bNeedsIVw.tintColor= [UIColor whiteColor];
[post_bNeeds_BTN addSubview:bNeedsIVw];
Step 3:
//also set UILable on UIButton
UILabel *bNeedsLbl= [[UILabel alloc] initWithFrame:CGRectMake(40 ,0 ,post_Prod_BTN.frame.size.width-40 ,post_Prod_BTN.frame.size.height)];
bNeedsLbl.text= @"Requirements";
bNeedsLbl.font= [UIFont systemFontOfSize:16];
bNeedsLbl.textColor= [UIColor whiteColor];
bNeedsLbl.textAlignment= NSTextAlignmentLeft;
[post_bNeeds_BTN addSubview:bNeedsLbl];
Step 4:
-(void)post_Buying_Needs_BTN_Pressed:(id)sender{
//write your code action here,,
}
thanks,
Upvotes: 1
Reputation: 16931
One trick is to:
titleRectForContentRect
to make the button's titleLabel
's frame
equal to the button's boundstitleLabel
's textAlignment
to .Center
override imageRectForContentRect
to specify the origin.x
of the button's imageView
import UIKit
class ButtonWithLeftAlignedImageAndCenteredText: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
titleLabel?.textAlignment = .Center
}
override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
var imageFrame = super.imageRectForContentRect(contentRect)
imageFrame.origin.x = 20 //offset from left edge
return imageFrame
}
override func titleRectForContentRect(contentRect:CGRect) -> CGRect {
var titleFrame = super.titleRectForContentRect(contentRect)
titleFrame = self.bounds
return titleFrame
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Upvotes: 2
Reputation: 3379
This works well for me, for several buttons, with different image width and different title length :
Subclass UIButton
, and add the following method:
override func layoutSubviews() {
super.layoutSubviews()
if let image = imageView?.image {
let margin = 30 - image.size.width / 2
let titleRect = titleRectForContentRect(bounds)
let titleOffset = (bounds.width - titleRect.width - image.size.width - margin) / 2
contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left
imageEdgeInsets = UIEdgeInsetsMake(0, margin, 0, 0)
titleEdgeInsets = UIEdgeInsetsMake(0, (bounds.width - titleRect.width - image.size.width - margin) / 2, 0, 0)
}
}
Upvotes: 5
Reputation: 9878
I see a lot of solutions here that focus on setting the icon to the left. I think it's way easier to just add a UIImageView, align the left sides of the button and the image and center them together as well. Then you can play a bit with the offset to make it look nice.
No code, all in Interface Builder.
Upvotes: 2
Reputation: 1215
As I think, the good solution must be useful for any text, without hardcoded values for insets (it's about the solution provided by toytoy). I use the code similar to this:
NSString *sometitle = @"blabla button title";
NSString *someimage = @"blablaimage";
UIImage *image = [[UIImage imageNamed:someimage];
int buttonWidth = A;
int buttonHeight = B;
int imageWidth =image.size.width;
int imageHeight = image.size.height;
int titleWidth = buttonWidth - imageWidth;
// create button and set image and title
buttonView = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, buttonWidth, buttonHeight)];
[buttonView setImage:image forState:UIControlStateNormal];
[buttonView setTitle:sometitle forState:UIControlStateNormal];
// make button all content to be left aligned
[buttonView setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
// set title font
[buttonView.titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:14]];
// calculate font text width with selected font
CGSize stringBoundingBox = [number sizeWithFont:[buttonView.titleLabel font]];
// make title inset with some value from left
// it place the title right on the center of space for the title
int titleLeft = (titleWidth - stringBoundingBox.width) / 2;
[buttonView setTitleEdgeInsets:UIEdgeInsetsMake(0, titleLeft, 0, 0)];
After the string with stringBoundingBox init I also add some strings like this:
if (stringBoundingBox.width > titleWidth)
{
[_backgroundView.titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:13]];
stringBoundingBox = [number sizeWithFont:[_backgroundView.titleLabel font]];
}
if (stringBoundingBox.width > titleWidth)
{
[_backgroundView.titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:12]];
stringBoundingBox = [number sizeWithFont:[_backgroundView.titleLabel font]];
}
it allow to me set the titles longer than available space, by selecting some smaller fonts. I make this because of another way for this:
[buttonView.titleLabel setAdjustsFontSizeToFitWidth:YES];
works not very good, looks like it take the font size for 3-4 points smaller at one step, so some not so long lines become too smaller, than it must to be.
This code allow us to place any text in button title space exactly in center.
Upvotes: 9
Reputation: 3327
Create your button and set the text alignment to center, then add:
UIImage *image = [UIImage imageNamed:@"..."];
CGSize imageSize = image.size;
CGFloat offsetY = floor((self.layer.bounds.size.height - imageSize.height) / 2.0);
CALayer *imageLayer = [CALayer layer];
imageLayer.contents = (__bridge id) image.CGImage;
imageLayer.contentsGravity = kCAGravityBottom;
imageLayer.contentsScale = [UIScreen mainScreen].scale;
imageLayer.frame = CGRectMake(offsetY, offsetY, imageSize.width, imageSize.height);
[self.layer addSublayer:imageLayer];
Upvotes: 8
Reputation: 4243
1) button.frame = self.view.bounds;
2) setImageEdgeInsets
with negative values, when your button fills the screen, is madness. Reconsider what you're trying to do here?
3) UITextAlignmentCenter
is now NSTextAlignmentCenter
4) button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
Upvotes: 3
Reputation: 1714
It might be best to create a custom UIButton subclass to address this issues in a better manner. Apple might be 'resetting' your settings.
Upvotes: -2