UIButton label text autoshrink with insets - ios

I am using Auto Layout. I have a UIButton with a fixed height and width and a background image (a rounded square). It displays text strings of variable length (between 1 and 30 words, let's say).
I wanted to make the text autoshrink depending on string length, and to have up to 3 lines of text in my button. So I did this:
[button.titleLabel setMinimumScaleFactor:0.01];
[button.titleLabel setAdjustsFontSizeToFitWidth: YES];
[button.titleLabel setNumberOfLines:3];
[button.titleLabel setTextAlignment:NSTextAlignmentCenter];
I also set the font size to a high value like 50 in the Interface Builder. And I set the line break to "Clip".
The button's text correctly adapts to the number of characters, but it tends to go beyond the frame of the button. It does that for mid-length strings but not for huge strings and I have no idea why. I have tried to add insets to my button but it doesn't do much, only moves the overly-big text around, so I assume the font adjustment is calculated prior to the incorporation of insets.
Below a screenshot. There are 4 of those buttons, contained within the bigger blue view. The red background is the background of the button, the yellow is an image that serves as background.
I uploaded an example project on Google Drive. Use iPhone 6 Plus for simulation.

You should also set your button's titleEdgeInsets property.
For instance:
button.titleEdgeInsets = UIEdgeInsetsMake(2.0, 2.0, 2.0, 2.0);
In your project, it seems that there some layout constraints that are messing with the buttons' title label.
When adding the following constraints, it works.
UILabel *titleLabel = button.titleLabel;
NSDictionary *views = NSDictionaryOfVariableBindings(titleLabel);
[button addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[titleLabel]|"
options:kNilOptions
metrics:nil
views:views]];
Before using this solution, I suggest you first try to set your layout constraints in a simpler way if possible.

Related

How do you tighten UILabel's sizeToFit to use smaller margins?

I'm creating a UILabel, adding some text, and then calling [myLabel sizeToFit], which resizes the label to fit the text. However, I'm noticing some margin -- or edge insets -- to the left and right, almost as if it's purposely buffering my text.
I'm very short on space, and I'd like to run sizeToFit without these margins, i.e. I want the last pixel of my text to run up against the bounds on left & right. How do I accomplish this?
- (void) layoutGroupTabLabeled:(NSString*)title {
// Determine how long a label we need:
UILabel* label = [[UILabel alloc] init];
label.text = NSLocalizedString(title, #"");
[label sizeToFit];
}
The label should be tight, but has space to left & right.
The answer to your problem is using AutoLayout constraints. In your case it should be covered by adding leading and trailing constraints to the label.
If you don't know your way around AutoLayout I recommend checking these answers.
Adding constraints programmatically in Objective-C

How can I place a UILabel below an UIImageView such that it is always evenly placed

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);
}];

Enlarge UIButton text?

I use Masonry library to create Auto Layout constraints programmatically. Here is my code for creating UIButton:
readNext = [UIButton buttonWithType:UIButtonTypeRoundedRect];
readNext.titleLabel.adjustsFontSizeToFitWidth = YES;
readNext.titleLabel.lineBreakMode = NSLineBreakByClipping;
[readNext setTitle:#"Читать дальше" forState:UIControlStateNormal];
[self.view addSubview:readNext];
[readNext mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(#160);
make.height.equalTo(#80);
make.right.equalTo(newsContainerView.mas_right).with.offset(-20);
make.bottom.equalTo(newsContainerView.mas_bottom).with.offset(-20);
}];
Basically its mean that i create button that aligned to right and bot of view, and width of that button is 160 points, and height is 80. However, the label text font is too small. Even when i expand width or height (or both) its no changing. How to fix that?
There is no property available to increase font size as frame size increases.
adjustsFontSizeToFitWidth is a Boolean value indicating whether the font size should be reduced in order to fit the title string into the label’s bounding rectangle.
What you can probably do is set font of titleLabel to some large value say 100 and set adjustsFontSizeToFitWidth to true. Thus that will make your font size shrink automatically so that text adjusts in the given frame size.

UIButton takes up its own size Autolayout

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.

UIButton vertical alignment doesn't work

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.

Resources