I have made a custom pop view which looks like this
I want to place the label of user name below the user image which is the rounded UIImageView in the given image
I want the user name to be placed evenly irrespective of the size of the text.
Like I want the name to appear like this
Align the Label content to Center.
Set a constraint from label to Image View. Horizontally center label to Image View.
As you are not using the storyboard, Below code will help you in setting the frame of label:-
UILabel *labelName;//This will be your label instance
CGFloat yAxis = 50;//This will be your image view's y axis + image view's height
[labelName setFrame:CGRectMake(0, yAxis, self.view.frame.size.width, self.view.frame.size.height)];
//Set the color/Font other properties of label as desired
[labelName setTextAlignment:NSTextAlignmentCenter];
Setting the constraint is the efficient solution.
Either you can follow the storyboard way as suggested by Mr.UB or the approach it by code way.I suggest you to use Masonry for setting the constraints if you wish to proceed by code.
And you can simply do:
[your-label mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(imgView.mas_top); //with is an optional semantic filler
make.mas_centerX.equalTo(imgView.mas_centerX);
}];
What I tried was this :-
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:btn];
btn.translatesAutoresizingMaskIntoConstraints = NO;
[btn addTarget:self action:#selector(bringUpNextViewController:)
forControlEvents:UIControlEventTouchUpInside];
btn.titleLabel.font = [UIFont fontWithName:#"HelveticaNeue" size:14];
[btn setTitle:#"8" forState:UIControlStateNormal];
[self.view layoutIfNeeded];
NSLog(#"button size : %#", NSStringFromCGSize(btn.frame.size));
As output, I get this :
button size : {30, 29}
Then I gave setTitle string as nothing. The button width was still 30.
So why is this the case always?
I also tried giving a high compression resistance priority and high content hugging priority. Doesn't shrink to nothing.
The problem is also the fact that I want to reduce the width of the button simply based on its content, without giving any fixed width.
I could take the width of text and give the button the width, but I shouldn't be needing to do that either if the button was taking up the content width.
EDIT:
Its not the insets either which is causing the width to be 30. Ghost value.
A button is made of several subviews. It's very likely that the internal layout of a button has some default padding between the label and the button view itself.
Making a button like yours and examining the constraints shows the following:
button constraints (
"<NSContentSizeLayoutConstraint:0x8c40a60 H:[UIButton:0x8f29840(30)] Hug:250 CompressionResistance:750>",
"<NSContentSizeLayoutConstraint:0x8c55280 V:[UIButton:0x8f29840(29)] Hug:250 CompressionResistance:750>"
)
The 30 and 29 tie up with the size values you are seeing. The intrinsic content size property of the button also returns 30,29. Basically this is the minimum size for a button, in the absence of anything else.
It's not quite clear what you want or why you are bothered by this. Anything smaller will be a poor touch target, and a button with no label or image will be invisible anyway. If you add a longer title, the button will get bigger. If you add other constraints to force particular sizes, then these will override the intrinsic content size.
If you want the button to become invisible when it has no title, then you should explicitly hide it. This makes your intentions in the code much clearer and will prevent the user from accidentally hitting a button they can't really see.
I'm wondering if there is a minimum intrinsic content size for a uibutton?
Anyway, try doing...
[button invalidateIntrinsicContentSize];
Did you try [button sizeToFit];?
For custom buttons, I think that you will need to override:
- (CGSize)sizeThatFits:(CGSize)size;
Finally, if nothing other works, you can always try giving the button width from the text size like so
CGSize textsize = [yourText sizeWithFont:[UIFont fontWithName:#"HelveticaNeue" size:14]];
[button setFrame:CGRectMake(0,0,textsize.width, textsize.height)];
First define a constraint for button size in storyboard.
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *buttonSizeConst;
After that you can set it's size to whatever you want like this.
self.buttonSizeConst.constant = 65.0;
Edit: With this method you need to calculate your button width but I think you don't want to do that. You need to autoresize UIButton for it's content. For this you should give constraints like image below. It will expand to right when you change your title.
I can't figure why in the following code, the title alignment isn't remain Top.
UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn2.titleLabel.font = [UIFont systemFontOfSize:53];
btn2.frame = CGRectMake(20, 20, 270, 44);
[btn2 setTitle:#"test1 test2 test3 test4 test5 test6 test7" forState:UIControlStateNormal];
[btn2 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
btn2.titleLabel.minimumFontSize = 1.0;
btn2.titleLabel.adjustsFontSizeToFitWidth = YES;
btn2.titleLabel.numberOfLines = 1;
btn2.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
UIButton has a very nifty property named "titleEdgeInsets" which you can use (via UIEdgeInsetsMake to reposition the top and bottom margins of the title and get the thing centered, vertically.
This behavior is due to the baselineAdjustment default property of the button's titleLabel. If you set this to UIBaselineAdjustmentNone, you should get the effect you're looking for.
btn2.titleLabel.baselineAdjustment = UIBaselineAdjustmentNone;
From the docs for UILabel:
baselineAdjustment
Controls how text baselines are adjusted when text
needs to shrink to fit in the label.
#property(nonatomic) UIBaselineAdjustment baselineAdjustment
Discussion
If the adjustsFontSizeToFitWidth property is set to YES, this property controls the behavior of the text baselines in situations where adjustment of the font size is required. The default value of this property is UIBaselineAdjustmentAlignBaselines. This property is effective only when the numberOfLines property is set to 1.
and
UIBaselineAdjustmentAlignBaselines
Adjust text relative to the position of its baseline.
Available in iOS 2.0 and later.
UIBaselineAdjustmentAlignCenters
Adjust text based relative to the center of its bounding box.
Available in iOS 2.0 and later.
UIBaselineAdjustmentNone
Adjust text relative to the top-left corner of the bounding box. This is the default adjustment.
Available in iOS 2.0 and later.
Note that the default adjustment for UILabel differs from that of a button's titleLabel.
Have a look at Content-Alignment Vertical in storyboard
I gave up trying to get this to work programmatically and just set a baseline constraint to another item. It seems to work great on IB (the content alignment property), even within a Stack View, but in code it does not work.
If I have a UIButton arranged using autolayout, its size adjusts nicely to fit its content.
If I set an image as button.image, the instrinsic size again seems to account for this.
However, if I tweak the titleEdgeInsets of the button, the layout does not account for this and instead truncates the button title.
How can I ensure that the intrinsic width of the button accounts for the inset?
Edit:
I am using the following:
[self.backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
The goal is to add some separation between the image and the text.
You can get this to work in Interface Builder (without writing any code), by using a combination of negative and positive Title and Content Insets.
Update: Xcode 7 has a bug where you cannot enter negative values in the Right Inset field, but you can use the stepper control next to it to decrease the value. (Thanks Stuart)
Doing this will add 8pt of spacing between the image and the title and will increase the intrinsic width of the button by the same amount. Like this:
You can solve this without having to override any methods or set an arbitrary width constraint. You can do it all in Interface Builder as follows.
Intrinsic button width is derived from the title width plus the icon width plus the left and right content edge insets.
If a button has both an image and text, they’re centered as a group, with no padding between.
If you add a left content inset, it’s calculated relative to the text, not the text + icon.
If you set a negative left image inset, the image is pulled out to the left but the overall button width is unaffected.
If you set a negative left image inset, the actual layout uses half that value. So to get a -20 point left inset, you must use a -40 point left inset value in Interface Builder.
So you provide a big enough left content inset to create space for both the desired left inset and the inner padding between the icon and the text, and then shift the icon left by doubling the amount of padding you want between the icon and the text. The result is a button with equal left and right content insets, and a text and icon pair that are centered as a group, with a specific amount of padding between them.
Some example values:
// Produces a button with the layout:
// |-20-icon-10-text-20-|
// AutoLayout intrinsic width works as you'd desire.
button.contentEdgeInsets = UIEdgeInsetsMake(10, 30, 10, 20)
button.imageEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0)
Why not override the intrinsicContentSize method on UIView? For example:
- (CGSize) intrinsicContentSize
{
CGSize s = [super intrinsicContentSize];
return CGSizeMake(s.width + self.titleEdgeInsets.left + self.titleEdgeInsets.right,
s.height + self.titleEdgeInsets.top + self.titleEdgeInsets.bottom);
}
This should tell the autolayout system that it should increase the size of the button to allow for the insets and show the full text. I'm not at my own computer, so I haven't tested this.
You haven't specified how you're setting the insets, so I'm guessing that you're using titleEdgeInsets because I see the same effect you're getting. If I use contentEdgeInsets instead it works properly.
- (IBAction)ChangeTitle:(UIButton *)sender {
self.button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
[self.button setTitle:#"Long Long Title" forState:UIControlStateNormal];
}
And for Swift worked this:
extension UIButton {
override open var intrinsicContentSize: CGSize {
let intrinsicContentSize = super.intrinsicContentSize
let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom
return CGSize(width: adjustedWidth, height: adjustedHeight)
}
}
Love U Swift
This thread is a bit old, but I just ran into this myself and was able to solve it by using a negative inset. For example, substitute your desired padding values here:
UIButton* myButton = [[UIButton alloc] init];
// setup some autolayout constraints here
myButton.titleEdgeInsets = UIEdgeInsetsMake(-desiredBottomPadding,
-desiredRightPadding,
-desiredTopPadding,
-desiredLeftPadding);
Combined with the right autolayout constraints, you end up with an auto-resizing button which contains an image and text! Seen below with desiredLeftPadding set to 10.
You can see that the actual frame of the button doesn't encompass the label (since the label is shifted 10 points to the right, outside the bounds), but we've achieved 10 points of padding between the text and the picture.
I wanted to add a 5pt space between my UIButton icon and the label. This is how I achieved it:
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
// more button config etc
infoButton.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 5);
infoButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, -5);
The way contentEdgeInsets, titleEdgeInsets and imageEdgeInsets relate to each other requires a little give and take from each inset. So if you add some insets to the title's left you have to add negative inset on the right and provide some more space (via a positive inset) on the content right.
By adding a right content inset to match the shift of the title insets my text doesn't go outside the bounds of the button.
For Swift 3 based on pegpeg's answer:
extension UIButton {
override open var intrinsicContentSize: CGSize {
let intrinsicContentSize = super.intrinsicContentSize
let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom
return CGSize(width: adjustedWidth, height: adjustedHeight)
}
}
All above did not work for iOS 9+, what i did is:
Add a width constraint (for a minimum width when the button doesn't have any text. The button will auto scale if text is provided)
set the relation to Greater Than or Equal
Now to add a border around the button just use the method:
button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
The option is also available in interface builder. See the Inset. I set left and right to 3. Works like a charm.
The solution I use is to add a width constraint on the button. Then somewhere in initialization, after your text is set, update the width constraint like so:
self.buttonWidthConstraint.constant = self.shareButton.intrinsicContentSize.width + 8;
Where 8 is whatever your inset is.
I have a UIButton which has a title longer than the width of the button itself. While in a UITextField I see the first part of the string (which is the one I want to show) and then three dots, on the UIButton I see the first part, then towards the center three dots and then the third part. Is there a way to fix this issue without actually cutting the string?
If the button size can't change but the titleLabel size can, you can either change the font in of the button in interface builder or in code or allow the label to adjust its font with:
button.titleLabel.adjustsFontSizeToFitWidth = YES;
If the button size can change, you could adjust that rather then the font size:
CGRect frame;
frame.origin = self.button.frame.origin;
frame.size = [self.button.titleLabel.text sizeWithFont:self.button.titleLabel.font];
self.button.frame = frame;
Alternatively, if you want the line to break at the end of the string instead of the middle, similar to how a UITextField appears, just set the lineBreakMode to NSLineBreakByTruncatingTail