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.
Related
I am finding it surprisingly hard to resize a label containing newlines based on the quantity of lines and text. It displays fine in a large enough textview. However, I'd like the economy of sizing the label--or I'd be happy with resizing a textview--exactly.
This is the code I am using from an answer on SO but it is having no effect on the size of the label. Would appreciate any suggestions on how to make this work:
NSString *list = self.list.list;
// use font information from the UILabel to calculate the size
UITextView *view=[[UITextView alloc] initWithFrame:CGRectMake(0, 0, 280, 10)];
//make random size view
view.text=list;
CGSize size=[view sizeThatFits:CGSizeMake(280, CGFLOAT_MAX)];
// create a frame that is filled with the UILabel frame data
CGRect newFrame = _listLabel.frame;
// resizing the frame to calculated size
newFrame.size.height = size.height;
// put calculated frame into UILabel frame
_listLabel.frame = newFrame;
Why are you setting the frame of your label with reference of a newly created UITextView, it will create a useless object in your memory, to set the label frame according to your text just use this 2 line of code
lbl.numberOfLines=0;
[lbl sizeToFit];
It will make the label as large as your text.
You really should use autolayout.
Just constrain the label where you need and let UIKit do it's job.
Here an example:
I set a top space and a leading margin constraints
Then I added a width constraint and then I added some more text
As you can see the label resized itself as it knows how much text it has inside and how much space it occupies.
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.
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 have a UITextView containing some text that fills the whole width without overflowing.
I'm reducing the width of the UITextView by changing its frame in a block animation, such that the decreased width causes the text to overflow and the end to be replaced with an ellipsis ('...').
Currently, the text does not respond smoothly to the changing width. It jumps from the full width case to the truncated '...' case without anything in between, and the same when animating back to the full width.
Is it possible to force the text to change and the ellipsis to be introduced/removed smoothly as the frame animates?
You should use the answer here: UITextView animating change of frame does not animate text reallocation
The text in textviews doesn't always act as expected. For this you'll have to set up a NSTimer and set the frame size on every tick.
Do something like:
textview.frame = CGRectMake (textview.frame.origin.x, textview.frame.origin.y, textview.frame.size.width-1, textview.frame.size.height-1);
Then when it's done I would completely remove the textview from superview and set it to nil, and then init a new one. The reason for this is that when changes the frames of textviews for some reason padding is added around the text's box. You won't notice it unless you change the frame a probably at least 100 times.
[textview removeFromSuperview];
textview = nil;
textview = [[UITextView alloc] initWithFrame:CGRectMake(x, y, width, height)];
textview.text = yourTextString;
//You will also have to set whatever non default properties you want, such as text or background color
[view addSubview:textview];
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.