iPhone UIButton - image position
Solution 1
Here is my own way to do the thing, (after about 10 years)
- Subclass from UIButton (Button, as we're living in Swift era)
- Put an image and a label in a stack view.
class CustomButton: Button {
var didLayout: Bool = false // The code must be called only once
override func layoutSubviews() {
super.layoutSubviews()
if !didLayout, let imageView = imageView, let titleLabel = titleLabel {
didLayout = true
let stack = UIStackView(arrangedSubviews: [titleLabel, imageView])
addSubview(stack)
stack.edgesToSuperview() // I use TinyConstraints library. You could handle the constraints directly
stack.axis = .horizontal
}
}
}
Solution 2
My solution to this is quite simple
[button sizeToFit];
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width);
Solution 3
On iOS 9 onwards, seems that a simple way to achieve this is to force the semantic of the view.
Or programmatically, using:
button.semanticContentAttribute = .ForceRightToLeft
Solution 4
Set the imageEdgeInset
and titleEdgeInset
to move the components around within your image. You could also create a button using those graphics that is full size, and use that as the background image for the button (then use titleEdgeInsets
to move the title around).
Solution 5
Raymond W's answer is best here. Subclass UIButton with custom layoutSubviews. Extremely simple to do, here's a layoutSubviews implementation that worked for me:
- (void)layoutSubviews
{
// Allow default layout, then adjust image and label positions
[super layoutSubviews];
UIImageView *imageView = [self imageView];
UILabel *label = [self titleLabel];
CGRect imageFrame = imageView.frame;
CGRect labelFrame = label.frame;
labelFrame.origin.x = imageFrame.origin.x;
imageFrame.origin.x = labelFrame.origin.x + CGRectGetWidth(labelFrame);
imageView.frame = imageFrame;
label.frame = labelFrame;
}
Pavel Yakimenko
Updated on November 19, 2020Comments
-
Pavel Yakimenko over 3 years
I have a
UIButton
with text "Explore the app" andUIImage
(>) InInterface Builder
it looks like:[ (>) Explore the app ]
But I need to place this
UIImage
AFTER the text:[ Explore the app (>) ]
How can I move the
UIImage
to the right? -
Steven Kramer almost 13 yearsThis is so much easier than all the other advice (like the one above) about trying to place everything correctly using hand-tuned insets.
-
Pavel Yakimenko over 12 yearsThis way is better in the case you need to manage many buttons, but I need to change only one button :)
-
Kim about 11 yearsIt is much less code to simply set the insets than to implement a subclass. This is the whole point of the insets. Manipulating frames for sub views (that you have not created) feels more like a hack.
-
Scakko about 11 yearsIf the button image is nil the label results misplaced, probably because the UIImageView is not inserted (Tested on iOS6.0). You should consider editing frames only if imageView.image is not nil.
-
PokerIncome.com almost 11 yearsThis works great! It's hard to understand the edge inset concept. Any idea why we need to set both left and right edge inset? Theoretically, if I move the title to left and the image to right, that would be enough. Why do I need to set both left and right?
-
Kirk Woll over 10 years@kimsnarf, really? It's a lot less work (and less of a hack) to tweak the insets whenever you make a minor change in the size of the image or the length of the title?
-
Bimawa over 10 yearsTHE BEST SOLUTION I'VE FOUND
-
i-konov about 10 yearsI would suggest the following improvement to this answer so both views stay centered: 'CGFloat cumulativeWidth = CGRectGetWidth(imageFrame) + CGRectGetWidth(labelFrame) + 10; CGFloat excessiveWidth = CGRectGetWidth(self.bounds) - cumulativeWidth; labelFrame.origin.x = excessiveWidth / 2; imageFrame.origin.x = CGRectGetMaxX(labelFrame) + 10;'
-
mclaughj about 10 yearsThis answer works perfectly. The accepted answer is correct, and points to the correct API docs, but this is the copy and paste solution to do what the OP requested.
-
Brad G about 9 yearsBecomes a bit complicated when you start changing the button text. The subclassed solution worked better for me in this case.
-
rounak almost 9 yearsThis breaks on iOS 7 for me. Anyone else? Works fine on iOS 8.
-
Gil Sand over 8 yearsDon't support iOS7 at all and your problem will be gone. You shouldn't supoprt it anyway.
-
Toby over 8 yearsThank you for showing me you have to apply equal widths to left and right sides, I don't 100% understand how it works (because sometimes it will affect the size as well as origin) but I've been able to solve similar issues using this method.
-
farzadshbfn almost 8 yearsAs much as i liked your answer (+1), I hate to say it might not be the "proper" way to do this, but it's one of the easiest.
-
Alvivi almost 8 years@farzadshbfn you are right. I changed that word for "simple", seems more consistent.
-
Joe Susnick almost 8 yearsThanks! I like this a lot more than the answers that subclass and override layoutSubviews() :)
-
DrPatience about 7 yearsBest way to go about this in my humble opinion :)
-
manmal almost 6 yearsOf course
.forceRightToLeft
is an option! Just use the opposite value (.forceLeftToRight
) ifUIApplication.shared.userInterfaceLayoutDirection == .rightToLeft
. -
Samman Bikram Thapa about 5 years@farzadshbfn Why would this not be the "proper" way to do?
-
farzadshbfn about 5 years@SammanBikramThapa IMHO the proper way would be to subclass the UIButton and override layoutSubviews and respect
semanticContentAttribute
in our layout logic, instead of changingsemanticContentAttribute
itself. (changing semantic approach, will not work well with internationalization) -
Pavel Yakimenko over 4 years@farzadshbfn is totally right. No matter this answer scores most points it's not correct - It may break UX for right to left interface.
-
Pavel Yakimenko almost 4 yearsIt is not good as it will break the layout for all RTL users. You will need to force left to right for them. You better try other solution from here.
-
Vyachaslav Gerchicov almost 3 years"right-to-left"l is used for "right-to-left" languages like Arabic. So it is a bad approach to use it for something else.
-
kiran over 2 years@Alvivi it do have top button too ?