1

For example, is a button like this achievable?

enter image description here

I've seen questions like this where they go over how to put it before, which is indeed quite easy, but I'm not totally sure how to append it to the end of the text on the button when the text can be anything really. Conceptually, it would be something like having text, and then a UIButton say 10pt to the right of it.

Would the best way to do this simply be a UIView with a UILabel and a UIImageView inside it, with a tap gesture recognizer attached?

Community
  • 1
  • 1
Doug Smith
  • 29,668
  • 57
  • 204
  • 388

3 Answers3

1

A quick sample :

- (void)viewDidLoad
{
    [super viewDidLoad];
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

    UIImage *img = [UIImage imageNamed:@"Arrow.png"];
    [button setTitle:@"A Button" forState:UIControlStateNormal];
    [button setImage:img forState:UIControlStateNormal];
    [button sizeToFit];

    CGRect imageRect = [button imageRectForContentRect:button.bounds];
    CGRect titleRect = [button titleRectForContentRect:button.bounds];

    UIEdgeInsets imageInset = UIEdgeInsetsZero;
    UIEdgeInsets titleInset = UIEdgeInsetsZero;

    titleInset.left = -2 * imageRect.size.width;
    imageInset.left = titleRect.size.width;

    button.titleEdgeInsets = titleInset;
    button.imageEdgeInsets = imageInset;
    [self.view addSubview:button];

    CGFloat prevHeight = button.frame.size.height;
    UIButton *anotherButton = [UIButton buttonWithType:UIButtonTypeCustom];

    [anotherButton setTitle:@"Another Button" forState:UIControlStateNormal];
    [anotherButton setImage:img forState:UIControlStateNormal];
    [anotherButton sizeToFit];

    imageRect = [anotherButton imageRectForContentRect:anotherButton.bounds];
    titleRect = [anotherButton titleRectForContentRect:anotherButton.bounds];

    imageInset = UIEdgeInsetsZero;
    titleInset = UIEdgeInsetsZero;

    titleInset.left = -2 * imageRect.size.width;
    imageInset.left = titleRect.size.width;

    anotherButton.titleEdgeInsets = titleInset;
    anotherButton.imageEdgeInsets = imageInset;

    CGRect frame = anotherButton.frame;
    frame.origin.y += prevHeight + 4;

    [anotherButton setFrame:frame];

    [self.view addSubview:anotherButton];
}

Result for 2 buttons create like this

You just need to adjust buttons size and insets, if you want to add space between title and image.

Emmanuel
  • 2,897
  • 1
  • 14
  • 15
  • Where does the frame of the first button get defined? And is `sizeToFit` necessary? – Doug Smith Dec 01 '13 at 17:47
  • @DougSmith `sizeToFit` calculate the size of the button. So yes its necessary to send it, if you don't define a frame yourself. Without `sizeToFit` button.bounds and other rects will be equals to CGRectZero. – Emmanuel Dec 01 '13 at 18:18
  • With this snippet in viewDidLoad the method never gets called when the button is tapped: https://gist.github.com/anonymous/28f2d5536ff2c1bd9482 – Doug Smith Dec 01 '13 at 18:52
  • @DougSmith Work without problem with `UIControlEventTouchUpInside` and `UIControlEventTouchUpOutside` in my tests, be careful you use `UIControlEventTouchUpOutside`. – Emmanuel Dec 01 '13 at 19:02
  • Because I'm an idiot, thanks for catching that. My very last question is if I put it as `navigation.titleView` it works awesomely, but I'd like it centred based on the text, not the whole button (so therefore it would be slightly more to the right). Is it possible to push it more to the right if I set it to the titleView? – Doug Smith Dec 01 '13 at 19:08
  • @DougSmith It may be possible, but not without some work like subclassing UIButton. And this is a different question. – Emmanuel Dec 02 '13 at 07:14
0

You could also just have a UILabel and a UIImageView and an invisible UIButton on top of them.

Or as you said, a UIView with you custom content and a gesture recognizer. In that case however it might be more difficult to achieve the same behavior as a regular button (no highlighting, you can't move your finger before letting go, etc.)

Also, UIButton is a subclass of UIView. This means, you can easily add additional subviews (such as an UIImageView) inside the UIButton.

You could use an empty UIButton and put a UILabel and a UIImageView into it. And use Auto Layout to position them inside the button.

DrummerB
  • 39,814
  • 12
  • 105
  • 142
  • Seems you can't add additional subviews to a UIButton in Interface Builder. Best to do in code then I assume? – Doug Smith Dec 01 '13 at 16:37
  • Okay. When I use this snippet in `viewDidLoad`, the method never gets called. What am I doing wrong? https://gist.github.com/anonymous/7736502 – Doug Smith Dec 01 '13 at 16:46
  • There is a reason why you cannot add the image in Interface Builder. Apple considers subviews of standard controls its implementation details and advises against adding you own subviews: https://developer.apple.com/library/IOS/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/WindowsandViews/WindowsandViews.html#//apple_ref/doc/uid/TP40009503-CH2-SW26 – yurish Dec 01 '13 at 16:46
  • Ah, fair enough. The search continues. – Doug Smith Dec 01 '13 at 16:51
0

Just create UIButton

UIImage *arrowDownImage = [UIImage imageNamed:@"arrowDown.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:arrowDownImage forState:UIControlStateNormal];
[button setTitle:@"Test" forState:UIControlStateNormal];

// set image and title Inset 

[button setImageEdgeInsets:UIEdgeInsetsMake(<#CGFloat top#>, <#CGFloat left#>, <#CGFloat bottom#>, <#CGFloat right#>)];
[button setTitleEdgeInsets:UIEdgeInsetsMake(<#CGFloat top#>, <#CGFloat left#>, <#CGFloat bottom#>, <#CGFloat right#>)];

Play with Insets and this will give you exactly what you need.

This is IB example of button, but you can do the same programmatically.

enter image description here

And this is ImageInset

enter image description here

Title Inset

enter image description here

Eugene P
  • 554
  • 4
  • 19
  • What kind of insets should I be trying? – Doug Smith Dec 01 '13 at 17:09
  • Well^ if you what you image was inset from the left side of your button then use the (width of you button - width of your image) value, just play with this values and you figure out what it gives you. – Eugene P Dec 01 '13 at 17:10
  • I don't see how this works when the text changes. It seems that it needs to be hardcoded. – Doug Smith Dec 01 '13 at 17:14
  • If you button size changes dynamically, use button size to set Insets of the image and Text. – Eugene P Dec 01 '13 at 17:17
  • How do I get the button size without setting the frame? If I set the frame the size will never change, but if I use Auto Layout it seems that `button.bonds.size.width` is always 0. – Doug Smith Dec 01 '13 at 17:30