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
Related
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.
This question already has answers here:
How can I set the title of a UIButton as left-aligned?
(15 answers)
Closed 9 years ago.
I wish to align title and image in UiButton in such a manner that the title appears on the left and the image to the extreme right.
Please note that the button is stretched so as to fill the screen horizontally.
The button layout should look something like this:-
[title .. ]
The title should have some left padding.
The image should have some right padding.
CGFloat width = self.frame.size.width;
CGFloat imageWidth = [button currentImage].size.width;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
[button setTitleEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 0)];
[button setImageEdgeInsets:UIEdgeInsetsMake(0, width - imageWidth - 10, 0, 0)];
However, though the title is left align, there is a lot of space on it's left. The image does not show up at all!
Following Code will work
UIButton *sectionheader=[[UIButton alloc]initWithFrame:CGRectMake(0,0,320,44)];
[sectionheader setImageEdgeInsets:UIEdgeInsetsMake(0,6,0,0)];
sectionheader.userInteractionEnabled=NO;
[sectionheader setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
// Now Create Label and addsubview to button
UILabel *lblkey=[[UILabel alloc] initWithFrame:CGRectMake(0,0,sectionheader.frame.size.width-10,sectionheader.frame.size.height)];
lblkey.accessibilityValue=#"Value";
lblkey.font=[UIFont fontWithName:themefont size:20];
lblkey.text=[creteria uppercaseString];
lblkey.backgroundColor=[UIColor clearColor];
lblkey.shadowColor = [UIColor blackColor];
lblkey.shadowOffset = CGSizeMake(0, 2);
lblkey.textAlignment=NSTextAlignmentRight;
lblkey.textColor=[UIColor whiteColor];
[sectionheader addSubview:lblkey];
And suppoce you value is going to change always and you want to make it perfect than Make UIButton class and than add above code in that category class than just call following method to change value of that label
+(void)settitle:(NSString *)value:(UIButton *)selfbutton
{
for (UILabel *valuelabel in selfbutton.subviews)
{
if ([valuelabel.accessibilityValue isEqualToString:#"Value"])
{
valuelabel.text=value;
}
}
}
I will go with alternative What you can do is add three control in one view. lets say ParentView:
1) yourButton
2) yourlable // don't use button title instead use this lable.
3) imageView
now make the ParentView autosize like below:
so as yourButton will stretched horizontally it will automatically resize ParentView.
From here on you just want to take care about position.
set yourlable to extreme left in parentView after yourButton and set autosize property to:
so it will always remain to extreme left of ParentView
And set imageView position to extreme right in parentView and set autosize property to:
so it will always remain to extreme right of ParentView
Hope it will help.
if you have added button in xib and you want to set title and image then you can do it from Attribute inspector.
in attributeinspector there is an property named Edge. By default it has set content. but there are other two options named as Title and Image.
and exactly below Inset Property is there by which you can set title and image as you want. if you select title then you can set title (move left or right as u want) likewise for image also
I have a UIButton and it can change the title at the runtime. Therefore, I want to increase the UIButton height depend on the title text for display full text by using AutoLayout.
I can increase the UILabel height by set the height constraint to "Greater than or Equal" but it not work with UIButton.
I have used [myButton sizeToFit] but it only increase the UIButon width (not increase height).
My current UIButton properties now is
- constraint height: 30
- leading : 15
- trailing: 15
- top: 5
- fontsize: 12
UPDATE
I created an IBOutlet for constraint height of UIButton for changing the height as #NSNood said.
Then I need to use \n in title text to split line.
But I don't know where should I put the \n?
Here is the Button that I want in portrait
Here is the Button that I want in landscape
How can I determine the place to put \n?
Please guide me how to achieve it with AutoLayout. Any help would be appreciated.
Sorry that I didn't follow the post, lately and thus am coming up with a real late solution. Still I'm writing the answer as a reference, if someone might find it useful in future.
First of all let's show the storyboard configuration for the button. Those are depicted in the following pictures:
The picture shows that I have added only left, top and right constraints for the button and nothing else. This allows the button to have some intrinsicContentSize for it's height but it's width is still determined by it's left and right constraints.
The next phase is to write some ViewController class that shall contain the button. In my VC, I have created an outlet for the button by name button:
#property(nonatomic,weak) IBOutlet UIButton* button;
and has attached it to the storyboard button. Now I have overridden two methods, namely, viewDidLoad and viewWillLayoutSubviews like below:
-(void)viewDidLoad {
[super viewDidLoad];
self.button.titleLabel.numberOfLines = 0;
self.button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
-(void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self.button setTitle:#"Chapter One\n "
"A Stop on the Salt Route\n "
"1000 B.C.\n "
"As they rounded a bend in the path that ran beside the river, Lara recognized the silhouette of a fig tree atop a nearby hill. The weather was hot and the days were long. The fig tree was in full leaf, but not yet bearing fruit." forState:UIControlStateNormal];
}
The viewDidLoad method ensures the titleLabel (the label that
holds button text) is multiline and if some large text comes to it,
it wraps the text by wrapping words.
The viewWillLayoutSubviews method ensures button layouting process
occurs whenever bounds of the main view change, e.g. due to the
change of interface orientation.
The final and the most effective part is to manually handle the layout process for the button. For this purpose, we need to subclass UIButton. I have written a subclass named MyButton that inherits from UIButton and you might use whatever name you like. Set this as the custom class for the button in Identity Inspector.
The subclass overrides two methods, namely, intrinsicContentSize and layoutSubviews. The class body looks something like the following:
#import "MyButton.h"
#implementation MyButton
-(CGSize)intrinsicContentSize {
return [self.titleLabel sizeThatFits:CGSizeMake(self.titleLabel.preferredMaxLayoutWidth, CGFLOAT_MAX)];;
}
-(void)layoutSubviews {
self.titleLabel.preferredMaxLayoutWidth = self.frame.size.width;
[super layoutSubviews];
}
#end
The UIButon subclass takes the ownership of the layout process by overriding layoutSubviews method. The basic idea here is to determine the button width, once it has been layout. Then setting the width as preferredMaxLayoutWidth (the maximum width for layouting engine, that a multiline label should occupy) of it's child titleLabel (the label that holds button text). Finally, returning an intrinsicContentSize for the button based on it's titleLabel's size, so that the button fully wraps it's titleLabel.
The overridden layoutSubviews is called when the button is already
layed out and it's frame size is determined. At it's first step,
button's rendered width is set as preferredMaxLayoutWidth of the
button's titleLabel.
The second step re-invokes the layouting engine by calling [super
layoutSubviews], so that the buttons intrinsicContentSize is
re-determined based on it's titleLabel's
preferredMaxLayoutWidth, which is set to buttons rendered width,
by now.
In the overridden intrinsicContentSize method we return the
minimum fitting size for the button that fully wraps it's
titleLabel with preferredMaxLayoutWidth set. We use
sizeThatFits fits method on the button's titleLabel and that
simply works as titleLabel doesn't follow any constraint based
layout.
The outcome should be something similar to that you might have required.
Feel free to let me know about any other clarification/concern.
Thanks.
Ayan Sengupta solution in Swift, with support for contentEdgeInsets (thanks Claus Jørgensen):
(You may also further customize the code to take titleEdgeInsets into account if needed)
Subclass your UIButton to take the ownership of the layout process:
/// https://stackoverflow.com/a/50575588/1033581
class AutoLayoutButton: UIButton {
override var intrinsicContentSize: CGSize {
var size = titleLabel!.sizeThatFits(CGSize(width: titleLabel!.preferredMaxLayoutWidth - contentEdgeInsets.left - contentEdgeInsets.right, height: .greatestFiniteMagnitude))
size.height += contentEdgeInsets.left + contentEdgeInsets.right
return size
}
override func layoutSubviews() {
titleLabel?.preferredMaxLayoutWidth = frame.size.width
super.layoutSubviews()
}
}
Use this class in your storyboard, and set constraints for Leading, Trailing, Top, Bottom. But don't set any Height constraint.
An alternative without subclassing is to add a wrapper view as suggested by Bartłomiej Semańczyk answer and Timur Bernikowich comment.
The point is that if you set sizeToFit property, then the text will always be in one line and the width of the button will increase unless you put a next-line sign \n to explicitly say that you want it to be several lines.
You put '\n' in the end of the first line like "line \n line" which represents
line
line
If you want to have two different string values (with \n positioned differently) for Portrait and Landscape you can check the orientation condition using UIDeviceOrientation (UIDevice.currentDevice.orientation) described here and set a string value depending on the orientation of the device
There is a way I always used:
Add another reference UILabel which lineNumber=0 and the same width with the target button.
Do not set height constraint for the ref-UILable, and should set a height constraint for the button to adjust its height
Set the same text to the ref UILabel with the button.titleLable, sizeTofit it and get its frame.size.height
Use the height value to the height constraint of the target button. (Of course, the button.titleLabel linenumber should be set to 0 or more lines)
Done. :)
PS1. This way can be used for the button and ref-label in a scrollview.
PS2. In some case, we can not get the correct height of the ref-label because it cannot gain a correct frame.width in scrollview, especially when we use the trailling constraint. We could consider to define a fixed width to the ref-label before sizeTofit and obtain the correct height for target button use.