UIButton with both image and text possible? - ios

I have a button of size width 200 and height 270. I want to have text and image on the same button. Not as a background image on that text. Instead of this, I want to display the text with height 120 and image of height 150 on the same button. How to do it?

You can use this code,it will serve your purpose
.h file code
IBOutlet UIButton *testBtn;
.m file code
[testBtn setImage: [UIImage imageNamed:#"Image name.png"] forState:UIControlStateNormal];
[testBtn setTitleEdgeInsets:UIEdgeInsetsMake(70.0, -150.0, 5.0, 5.0)];
[testBtn setTitle:#"Your text" forState:UIControlStateNormal];
Adjust the coordinates and size of your button as your requirement.This is a sample code to guide you.
PS:Take a UIButton in the nib file>Make it a custom button>Connect the IBOutlet to your custom button in the nib file.Thats it.

The below code shows placing an image and text in a button using setImageEdgeInsets and setTitleEdgeInsets properties of UIButton class.
UIButton *butt=[UIButton buttonWithType:UIButtonTypeCustom ];
[butt setFrame:CGRectMake(0, 0, 100, 100)];
[butt setBackgroundImage:[UIImage imageNamed:#"sig.png"] forState:UIControlStateNormal];
[butt setImageEdgeInsets:UIEdgeInsetsMake(0.0, 0.0, 50.0, 0.0)];
[butt setTitleEdgeInsets:UIEdgeInsetsMake(75.0, 0.0, 0.0, 0.0)];
[butt setTitle:#"hello" forState:UIControlStateNormal];
[butt setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self.view addSubview:butt];

In Swift 3
let button = UIButton()
//make sure the image (jpg, png) you are placing in the button
//is about the right size or it will push the label off the button
//add image
let image = UIImage(named:"my_button_image")
button.setImage(image, for: .normal)
button.imageView?.contentMode = .scaleAspectFit
button.imageEdgeInsets = UIEdgeInsets(top:0, left:-30, bottom:0, right:0) //adjust these to have fit right
//add title
button.setTitle("Fan", for: .normal)
button.titleEdgeInsets = UIEdgeInsets(top:0, left:10, bottom:0, right:0) //adjust insets to have fit how you want
//add button to your view - like in viewDidLoad or your own custom view setup
addSubview(button)
Don't forget to set anchors if doing so programmatically for it to appear/attach it to your button reference in Interface Builder if using a storyboard

Yes, you can display an image and a title in the same button, as long as they are both small enough to fit. The hard part comes, when you need to deal with placement.
You can play with the contentVerticalAlignment and contentHorizontalAlignment properties of the UIButton (inherited from UIControl).
You can also use the titleEdgeInsets and imageEdgeInsets properties to shift the the title and image from the placement they get based on the alignment properties.
If you want very accurate or custom placement, I suggest overriding the titleRectForContentRect: and imageRectForContentRect: methods of the UIButton. These allow you to define the frames for your title and image, and they are called whenever the button needs to be laid out. One warning, if you want to reference self.titleLabel inside of titleRectForContentRect:, make sure self.currentTitle is defined first. I was getting a bad access error, , possibly the method is called when first initializing the titleLabel.

Use the concept of subviews. Take 3 controls, UIButton (200x270), UILabel (200x120) and UIImageView (200x150). Assign the image to the UIImageView and set the text for the UILabel. Position your label and imageview controls based upon the (x,y) location of the UIButton.
In the end, you should have something like:
For the following instances:
UIButton *button;
UILabel *label;
UIImageView *imageView;
[button addSubView:imageView];
[button addSubView:label];

[testBtn setBackgroudImage: [UIImage imageNamed:#"Image name.png"] forState:UIControlStateNormal];
[testBtn setTitle:#"Your text" forState:UIControlStateNormal];

If you want to have more control over the layout, create a subclass of UIControl and arrange the views you want (UILabel, UIImageView) in a xib file. Then you can use Autolayout regularly without having to sort out UIEdgeInsets.

swift version:
var button = UIButton()
newGameButton.setTitle("Новая игра", for: .normal)
newGameButton.setImage(UIImage(named: "energi"), for: .normal)
newGameButton.backgroundColor = .blue
newGameButton.imageEdgeInsets.left = -50

Using button subviews worked for me in Swift 4.
Create your button
Set an image for button
Create a label for the text
Add the label as a subview of your button
Constrain the label within the button
let imageAndTextButton : UIButton = {
let button = UIButton(frame: .zero)
button.tintColor = .clear
button.setImage(#imageLiteral(resourceName: "buttonImage"), for: .normal)
button.imageView?.contentMode = .scaleToFill
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let textForButtonLabel = UILabel(frame: .zero)
textForButtonLabel.translatesAutoresizingMaskIntoConstraints = false
textForButtonLabel.attributedText = NSAttributedString(string: "Text For Button", attributes: buttonTextAttributes)
textForButtonLabel.textAlignment = .center
textForButtonLabel.backgroundColor = .clear
imageAndTextButton.addSubview(textForButtonLabel)
imageAndTextButton.addConstraint(NSLayoutConstraint(item: textForButtonLabel, attribute: .centerX, relatedBy: .equal, toItem: imageAndTextButton, attribute: .centerX, multiplier: 1.0, constant: 0))
imageAndTextButton.addConstraint(NSLayoutConstraint(item: textForButtonLabel, attribute: .centerY, relatedBy: .equal, toItem: imageAndTextButton, attribute: .centerY, multiplier: 1.0, constant: 0))

Try this it's work for me ,
We have to set value of UIEdgeInsets base on our button size and requirement .
[self.testButton setTitle: #"myTitle" forState: UIControlStateNormal];
UIImage *iconImage = [UIImage imageWithIcon:#"fa-dot-circle-o" backgroundColor:[UIColor clearColor] iconColor:[UIColor whiteColor] fontSize:10.0f];
//UIEdgeInsets insets = {top, left, bottom, right};
[self.testButton setImageEdgeInsets:UIEdgeInsetsMake(3.0, 0.0, 3.0, 2.0)];
[self.testButton setTitleEdgeInsets:UIEdgeInsetsMake(3.0, 1.0, 3.0, 0.0)];
[self.testButton setImage:iconImage forState:UIControlStateNormal];
[self.testButton addTarget:self action:#selector(testButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.testButton];
Hope This will help for some one .

Related

UIBarButtonItem action selector ios11

UIButton *rideButton = [UIButton buttonWithType:UIButtonTypeCustom];
rideButton.titleLabel.font = CUSTOM_BUTTON_FONT;
[rideButton setTitleColor:[UIColor CUSTOM_BUTTON_TITLE_COLOR1] forState:UIControlStateNormal];
[rideButton setTitleColor:[UIColor CUSTOM_BUTTON_TITLE_COLOR2] forState:UIControlStateHighlighted];
[rideButton setTitle:#"Ride" forState:UIControlStateNormal];
[rideButton addTarget:self action:#selector(rideButtonClicked) forControlEvents:UIControlEventTouchUpInside];
CGSize s1 = [rideButton.titleLabel.text sizeWithFont:rideButton.titleLabel.font];
rideButton.frame = (CGRect) {
.size.width = (s1.width+rideBarButtonGap)>100?100:(s1.width+rideBarButtonGap),
.size.height = s1.height + rideBarButtonGap
};
rideButton.backgroundColor = [UIColor redColor];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11.0)
{
[[rideButton.widthAnchor constraintEqualToConstant:rideButton.frame.size.width] setActive:YES];
[[rideButton.heightAnchor constraintEqualToConstant:rideButton.frame.size.height] setActive:YES];
}
UIBarButtonItem *rideBarButton= [[UIBarButtonItem alloc] initWithCustomView:rideButton];
self.navigationItem.rightBarButtonItem = rideBarButton;
This is my code to create custom UIBarButtonItem. I have set the background color to red just to see the bounds of the button. The background color looks perfectly outside the text but I'm unable to click the button properly. The button's action get fired only when 'Ri' is selected. If 'de' is selected, the function is not called. It happens only in iOS 11. I have added width and height constraints to fix this but there is no change.
EDIT:
When I increase the width of widthAnchor, I'm able to acheive what I want but the button moves left and theres lot of gap between the button and Screen. So I tried to align the content using rideButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;. Though the content moves right, the clickable area is still in the middle.
Try this:
public extension UIView {
//From iOS 11 -> UIBarButtonItem uses autolayout instead of dealing with frames. so adding contraint for the barbuttonItem
public func applyNavBarConstraints(size: (width: CGFloat, height: CGFloat)) {
if #available(iOS 11.0, *) {
let widthConstraint = self.widthAnchor.constraint(equalToConstant: size.width)
let heightConstraint = self.heightAnchor.constraint(equalToConstant: size.height)
heightConstraint.isActive = true
widthConstraint.isActive = true
}
}}
and use it as below:
rideBarButton.applyNavBarConstraints(size: (width: 50, height: 44)) //expected height and width
This works for me. Hope this helps!

iOS 11 space between UIBarButtonItem

I've noticed that iOS 11 has made some change to the UIBarButtonItem. After solving the sizing problem of the image of UIBarButtonItem, I find myself facing another even more strange issue.
We have a UIToolBar with several UIBarButtonItems and we used to set the width of the UIBarButtonItem as 40 and the width of the UIButton.image as 24, which leaves a nice spacing between every two UIBarButtonItems. However, in iOS 11, the space disappear.
I tried with
[self.deleteButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(40, 24));
}];
NSLayoutConstraint *w = [self.deleteButton.imageView.widthAnchor constraintEqualToConstant:24];
NSLayoutConstraint *h = [self.deleteButton.imageView.widthAnchor constraintEqualToConstant:24];
w.active = YES;
h.active = YES;
but it doesn't work as I thought.
I either get a list of stretched images with CGSize(40, 24) or a list of UIBarButtonItem with CGSize(24, 24) lining up in the UINavigationBar one by one without spacing.
Are there anything other constraints I need to add to create the spacing?
Try this:
UIButton*(^buttonWith)(NSString *) = ^(NSString *imageName) {
CGFloat size = 40.0;
UIButton *button = [[UIButton alloc] initWithFrame: CGRectMake(0.0, 0.0, size, size)];
[button setImage: [[UIImage imageNamed: imageName] imageWithRenderingMode: UIImageRenderingModeAlwaysOriginal] forState: UIControlStateNormal];
[button addConstraint: [NSLayoutConstraint constraintWithItem: button attribute: NSLayoutAttributeWidth relatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 constant: size]];
[button addConstraint: [NSLayoutConstraint constraintWithItem: button attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 constant: size]];
return button;
};
Usage:
UIButton *resetButton = buttonWith(#"reset");
self.resetBarButton = [[UIBarButtonItem alloc] initWithCustomView: resetButton];
UIButton *backButton = buttonWith(#"back");
self.backBarButton = [[UIBarButtonItem alloc] initWithCustomView: backButton];
self.navigationItem.leftBarButtonItems = #[self.backBarButton, self.resetBarButton];
In storyboard you can place another UIBarButtonItem in between the buttons that need spacing. set the text to spaces only. see screen shots.

iOS: Navigation Controller title not centered

I have a navigation controller with a custom back button on the left. I do this programmatically so this is not an auto-layout issue. My problem is that the navigation controller title is not centered, it is going off the right side of the screen. I remember seeing a fix for this awhile back dealing with setting some type of fixed space as the right bar button item, but I cannot seem to find anything similar to this now.
Could someone tell me how to set the navigation controller title to centered and if the title is too big for its space, set nav bar title to fix its font size to fit the width of title space. This all needs to be done programmatically, thanks!
In navigation controller, by default, the view controller A that pushes current view controller B. The title of A will show up in backBarButton in view controller B.
The navigation controller title not centered is also because the previous view controller title is too long.
To counter that, use this in viewWillAppear of view controller A:
self.navigationItem.backBarButtonItem= UIBarButtonItem(title: "",
style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
self.navigationItem.backBarButtonItem!.title = ""`
Thanks so much for the answers, they were useful in helping my find a solution. My solution was to use the titleView property of the navigation controller. It sets the title without having to go through the trouble of making a custom UIView and the setAdjustsFontSizeToFitWidth property solved my problem of the font size being too big. I've added a little extra formatting to make it look nice, but I won't post it since it doesn't have to do with my question. Here is the code I am using:
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, self.view.frame.size.width-60, self.navigationController.navigationBar.frame.size.height)];
titleLabel.text = #"This is my big, long title";
titleLabel.textColor = [UIColor blackColor];
titleLabel.textAlignment = UITextAlignmentCenter;
[titleLabel setAdjustsFontSizeToFitWidth:YES];
self.navigationItem.titleView = titleLabel;
You have to add custom view in the navigation
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(10, 0, 150, 44)];
UILabel *titleLabel=[[UILabel alloc] initWithFrame:CGRectMake(10, 165,370, 25)];
titleLabel.text=#"Home";
titleLabel.textColor=[UIColor whiteColor];
[view addSubview:titleLabel];
[self.navigationController.navigationBar addSubview:view];
Try out this, it would help you and it is tested.
Objective C version
UIButton * button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 50, 50)];
[button addTarget:self action:#selector(yourSelector:) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"<" forState:UIControlStateNormal];
button.titleEdgeInsets = UIEdgeInsetsMake(-3, -15, 3, 15);
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
UIBarButtonItem *leftItem = [[UIBarButtonItem alloc]initWithCustomView:button];
self.navigationItem.leftBarButtonItem = leftItem;
Swift version
button = UIButton(frame: CGRectMake(0, 0,50, 50))
button?.addTarget(self, action: "backButtonTapped:", forControlEvents: UIControlEvents.TouchUpInside)
button?.setTitle("<", forState: .Normal)
button?.titleLabel?.font = UIFont(name: kFontHelveticaNeueRegular, size: 30)
button?.titleEdgeInsets = UIEdgeInsetsMake(-3, -15, 3, 15)
button?.setTitleColor(UIColor.whiteColor(), forState: .Normal)
var leftItem = UIBarButtonItem(customView: button!)
controller.navigationItem.leftBarButtonItem = leftItem
Add following method in your Utilities class
+ (void)setTitle:(NSString *)title forViewController:(UIViewController *)viewController {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setTextAlignment:NSTextAlignmentCenter];
[label setTextColor:[UIColor whiteColor]];
[label setFont:[UIFont boldSystemFontOfSize:18]];
[label setText:title];
[label sizeToFit];
viewController.navigationItem.titleView = label;
}
Use across view controllers as follows
[Utilities setTitle:#"Title for View Controller" forViewController:self];
Add both leftbarbutton and Rightbarbutton . Usually back button exist . If you add an empty right bar button , title will get centered.

iOS Create Button with two separate labels

I would like create a button with two independent labels.
I want to set in one button, two separate texts in different colors.
e.g.
[myButton setTitle: #"Title" forState: UIControlStateNormal];
[myButton setTitle2: #"Title2" forState: UIControlStateNormal];
Is it even possible? Maybe I should need to create a new control? Can anyone help me? I will be very grateful for a tutorial step by step.
If you wanted to do it all in Interface Builder you could place two UILabels where you want them in the view and then lay a UIButton over the top of them. Then with the Attributes Inspector change the UIButton's type to "Custom" and delete any existing label or placeholder text it has. This will make the button clear so both labels show through and you can set the UIButton's IBAction to do whatever you want to the two separate UILabels.
Also, you can do this :
UIButton *testButton = [UIButton buttonWithType:UIButtonTypeCustom];
testButton.frame = CGRectMake(0, 0, 200, 40);
[self.view addSubview:testButton];
UILabel *firstLineTestButton = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 20)];
firstLineTestButton.text = #"First line";
firstLineTestButton.font = [UIFont systemFontOfSize:12];
[testButton addSubview:firstLineTestButton];
UILabel *secondLineTestButton = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 200, 20)];
secondLineTestButton.text = #"Second line";
secondLineTestButton.font = [UIFont boldSystemFontOfSize:12];
[testButton addSubview:secondLineTestButton];
but the #vikingosegundo's solution is more appropriate for the new SDK
For iOS 6 and higher you can use setAttributedTitle:forState: to set an attributes string. A NSAttributedString can have many different attributes like text color.
Swift Version:
The following code also centres two titles both horizontally and vertically inside the button and has some font style adjustments.
let lineOne = UILabel.init(frame: CGRect(x: 0, y: self.button.frame.size.height / 4, width: self.button.frame.size.width, height: self.button.frame.size.height / 4))
lineOne.text = "Title 1"
lineOne.textColor = .black
lineOne.font = UIFont.boldSystemFont(ofSize: 13.0)
lineOne.textAlignment = .center
let lineTwo = UILabel.init(frame: CGRect(x: 0, y: lineOne.frame.size.height * 2, width: self.button.frame.size.width, height: self.button.frame.size.height / 4))
lineTwo.text = "Title 2"
lineTwo.textColor = .black
lineTwo.font = UIFont.boldSystemFont(ofSize: 13)
lineTwo.textAlignment = .center
self.button.addSubview(lineOne)
self.button.insertSubview(lineTwo, belowSubview: lineOne)
UIButton is a subclass of UIView. So you can add two different labels to your button using - (void)addSubview:(UIView *)view. Positioning could then be done either with Autolayout (if you are using that), or frames + springs/struts.

Is it possible to adjust x,y position for titleLabel of UIButton?

Is it possible to adjust the x,y position for the titleLabel of a UIButton?
Here is my code:
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];
[btn setTitle:[NSString stringWithFormat:#"Button %d", i+1] forState:UIControlStateNormal];
[btn addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
btn.titleLabel.frame = ???
//make the buttons content appear in the top-left
[button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[button setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];
//move text 10 pixels down and right
[button setTitleEdgeInsets:UIEdgeInsetsMake(10.0f, 10.0f, 0.0f, 0.0f)];
And in Swift
//make the buttons content appear in the top-left
button.contentHorizontalAlignment = .Left
button.contentVerticalAlignment = .Top
//move text 10 pixels down and right
button.titleEdgeInsets = UIEdgeInsetsMake(10.0, 10.0, 0.0, 0.0)
Swift 5
button.contentHorizontalAlignment = .left
button.contentVerticalAlignment = .top
button.titleEdgeInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 0.0, right: 0.0)
The easiest way to do it visually is to use the attribute inspector** (appears when editing a xib/storyboard), setting the "edge" property to title, adjusting it's insets, then setting "edge" property to image, and adjusting accordingly.
It's usually better than coding it , since it's easier to maintain and highly visual.
Derive from UIButton and implement the following method:
- (CGRect)titleRectForContentRect:(CGRect)contentRect;
Edit:
#interface PositionTitleButton : UIButton
#property (nonatomic) CGPoint titleOrigin;
#end
#implementation PositionTextButton
- (CGRect)titleRectForContentRect:(CGRect)contentRect {
contentRect.origin = titleOrigin;
return contentRect;
}
#end
For my projects I've this extension utility:
extension UIButton {
func moveTitle(horizontal hOffset: CGFloat, vertical vOffset: CGFloat) {
self.titleEdgeInsets.left += hOffset
self.titleEdgeInsets.top += vOffset
}
}
This can be done in xib. Select your button, go to "Show the Size Inspector" tab and setup insets.

Resources