I have found similar questions that ask how to have multi-line text on a UIButton, and the solution is to set
[myUIButton.titleLabel setLineBreakMode:UILineBreakModeWordWrap];
[myUIButton setTitle:myTitle forState:UIControlStateNormal];
However, this results in the button title taking up many lines. I have tried restricting the number of lines using
[myUIButton.titleLabel setNumberOfLines:2];
but this does not have any affect on the resulting number of lines.
Is there a way to limit the lines word wrapped to 2 lines on the UIButton title, and then have the tail truncated with "..."?
By setting lineBreakMode before numberOfLines your desired result can be achieved…
This is because lineBreakMode seems to cancel out numberOfLines set hence we are doing it in this order.
Objective-C:
[button.titleLabel setLineBreakMode: UILineBreakModeTailTruncation];
[button.titleLabel setNumberOfLines:2];
[button setTitle:myTitle forState:UIControlStateNormal];
Swift 3:
from Xcode 6 and above UILineBreakMode is replaced by NSLineBreakMode
button.titleLabel?.lineBreakMode = NSLineBreakMode.byTruncatingTail
button.titleLabel?.numberOfLines = 2
button.setTitle(myTitle, for: UIControlState.normal)
I know its been a while since the question was first asked, but I came across the same problem and endend up with a simple but functional solution after considering the answer posted
here.
The solution that worked for me was the following:
// Set the line break mode to word wrap so it won't truncate automatically
[button.titleLabel setLineBreakMode: UILineBreakModeWordWrap];
// Call a method that truncates the string I want to use
[button setTitle:[self truncateString:myButtonText] forState:UIControlStateNormal];
And the truncateString method:
- (NSString *)truncateString:(NSString *)stringToTruncate
{
if ([stringToTruncate length] > 50)
stringToTruncate = [[stringToTruncate substringToIndex:50] stringByAppendingString:#"..."];
return stringToTruncate;
}
So basically I calculated the number of characters that would work for my button, and then forced any string longer than that to have the '...' at the end. I know its not the ideal solution but I guess it can work for some of us, I hope it helps.
[button.titleLabel setNumberOfLines:2];
[button.titleLabel setLineBreakMode: UILineBreakModeTailTruncation];
[button setTitle:myTitle forState:UIControlStateNormal];
it does it for me! :D
cheers!!
Related
I have written the following code for my app:
self.PlayButton = [[UIButton alloc] init];
//Setup Play Button
[self.PlayButton setTranslatesAutoresizingMaskIntoConstraints:NO];
self.PlayButton.frame = CGRectMake(self.view.frame.size.width * 0.38, self.view.frame.size.height * 0.666, self.view.frame.size.width * 0.48, self.view.frame.size.height * 0.29);
[self.PlayButton setBackgroundImage:[UIImage imageNamed:#"PlayButton.png"] forState:UIControlStateNormal];
[self.PlayButton.layer setMagnificationFilter:kCAFilterNearest];
[self.PlayButton addTarget:self action:#selector(PlayButtonMethod) forControlEvents:(UIControlEvents)UIControlEventTouchUpInside]
[self.view addSubview:self.PlayButton];
But when this code it run rather than the image appearing in a rather specific location it simply appears in the top left hand corner of the view. Almost like it had been set
self.PlayButton.frame = CGRectMake(0, 0, self.view.frame.size.width * 0.48, self.view.frame.size.height * 0.29);
It's odd because the width and height is put in correctly but for whatever reason the position of the button set by the CGRectMake is not taken into account. Ive done a bit of research into creating UIButtons in code and fro what I've seen not only has this happened to no-one else the code have written is perfectly liable.
Any help would be appreciated.
Thanks
Looks like ive found the fix:
Removing this line of code fixed the issue for me.
[self.PlayButton setTranslatesAutoresizingMaskIntoConstraints:NO];
not 100% sure why this was causing the problem but it fixed it.
When creating UIButtons using the standard alloc init method doesn't actually create a button. The method for creating and initializing a UIButton is called buttonWithType:. This creates a UIButton of the specified type if you use alloc init it will not work correctly, see the Apple Documentation for UIButton.
So you need to change line
self.PlayButton = [[UIButton alloc] init];
to
self.PlayButton = [UIButton buttonWithType:UIButtonTypeCustom];
buttonWithType: allows you to pass in an enum of UIButtonType so it will accept any of the following values :
UIButtonTypeCustom
UIButtonTypeSystem
UIButtonTypeDetailDisclosure
UIButtonTypeInfoLight
UIButtonTypeInfoDark
UIButtonTypeContactAdd
UIButtonTypeRoundedRect
If you don't pass it a UIButtonType the button will not be initialized as it will not know what type of button you want and it will not assume. Also check out the Apple Documentation for UIButtonType
Side Note
I'm just going to include this as a side note. Also have a read of the Apple Coding Conventions Documentation as I have noticed that you are using uppercase to start your variable names (i.e. PlayButton). Variable names should start with lowercase (i.e. playButton) and Class and Enum names should start with uppercase (i.e. UIViewController). It's always good to stick to conventions as it makes you code more readable and maintainable so if another developer comes to modify your code it is easy for them or even yourself to read.
I'm trying to condense my code, and I know there's an easier way than writing out two separate lines, but I can't seem to get the syntax just right. What I'm essentially doing is assigning an image to my UIButton, passing it to a method to automatically resize it, and then setting the title to NULL. Any ideas?
My code :
[self.btnA setBackgroundColor:[UIColor colorWithPatternImage:[self resizeImageWithImage:[UIImage
imageNamed:#"A_3rdStroke.png"] toSize:CGSizeMake(100, 100)]]];
[self.btnA setTitle:#"" forState:UIControlStateNormal];
maybe:
- (void)setButton:(UIButton *)button withImageName:(NSString *)imageName {
[button setBackgroundColor:[UIColor colorWithPatternImage:[self resizeImageWithImage:[UIImage imageNamed:imageName] toSize:CGSizeMake(100, 100)]]];
[button setTitle:#"" forState:UIControlStateNormal];
}
and you can call it from your class like this:
[self setButton:self.btnA withImageName:#"A_3rdStroke.png"];
optionally, you could put such method into a category for the UIButton class (which needs to include your -resizeImageWithImage:toSize: method as well).
I'm trying to enable a button but the button that I would enable in this function changes. I have an array of the buttons but when I use the .enabled on the array index I want it says that this doesn't work for IDs.
I have used this array to set the text of each button before using:
[[ButtonArray objectAtIndex: Index] setTitle:(#"blahblahblah") forState: UIControlStateNormal];
is there any way to use a similar function call to enable and disable?
If you know for sure that everything in that array is a UIButton you can cast it to make the compiler happy:
[(UIButton *)[ButtonArray objectAtIndex: Index] setTitle:(#"blahblahblah") forState: UIControlStateNormal];
It's OK to split code up into multiple lines. It makes it easier to read, debug, and maintain.
UIButton *button = ButtonArray[Index]; // new, modern array syntax
button.enabled = YES;
[button setTitle:#"blah" forState:UIControlStateNormal];
I'm trying to make a UIButton that has two lines of text in its titleLabel. This is the code I'm using:
UIButton *titleButton = [[UIButton alloc] initWithFrame:CGRectMake(15, 10, frame.size.width-100, 100)];
titleButton.titleLabel.font = [UIFont boldSystemFontOfSize:24.0];
[titleButton setTitle:#"This text is very long and should get truncated at the end of the second line" forState:UIControlStateNormal];
titleButton.titleLabel.lineBreakMode = UILineBreakModeTailTruncation;
titleButton.titleLabel.numberOfLines = 2;
[self addSubview:titleButton];
When I try this, the text only appears on one line. It seems the only way to achieve more than one line of text in UIButton.titleLabel is to set numberOfLines=0 and use UILineBreakModeWordWrap. But this doesn't guarantee the text to be exactly two lines.
Using a plain UILabel, however, does work:
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(15, 10, frame.size.width-100, 100)];
titleLabel.font = [UIFont boldSystemFontOfSize:24.0];
titleLabel.text = #"This text is very long and should get truncated at the end of the second line";
titleLabel.numberOfLines = 2;
titleLabel.lineBreakMode = UILineBreakModeTailTruncation;
[self addSubview:titleLabel];
Does anyone know how to make the UIButton work with two lines? Is the only solution to create a separate UILabel to hold the text, and add it as a subview of the button?
You don't need to add a UILabel to the UIButton. That's just extra objects and work.
Set these properties on the titleLabel of your button.
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.numberOfLines = 2;//if you want unlimited number of lines put 0
Swift:
button.titleLabel!.lineBreakMode = NSLineBreakMode.ByWordWrapping
button.titleLabel!.numberOfLines = 2//if you want unlimited number of lines put 0
Updated answer for more recent iOS versions
Since this is the accepted answer, added #Sean's answer here:
Set these properties on the titleLabel of your button.
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.numberOfLines = 2; // if you want unlimited number of lines put 0
Swift 3 and 4:
button.titleLabel?.lineBreakMode = .byWordWrapping
button.titleLabel?.numberOfLines = 2 // if you want unlimited number of lines put 0
Original answer for an older version of iOS
If you want 2 lines of text on top of your UIButton you should add a UIlabel on top of it that does precisely that.
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(15, 10, frame.size.width-100, 100)];
titleLabel.font = [UIFont boldSystemFontOfSize:24.0];
titleLabel.text = #"This text is very long and should get truncated at the end of the second line";
titleLabel.numberOfLines = 2;
titleLabel.lineBreakMode = UILineBreakModeTailTruncation;
[myButton addSubview:titleLabel]; //add label to button instead.
Updated for interface builder solution
Added #Borut Tomazin's answer for a more complete answer.
Updated this part again since the answer of #Borut Tomazin was improved.
You can do this much easier, with no code required. In Interface Builder set Line Break on UIButton to Word Wrap. Than you can insert multiple lines of title. Just hit Option + Return keys to make new line. You will also need to add this to the User Defined Runtime Attribute in Interface Builder:
titleLabel.textAlignment Number [1]
You can do this much easier, with no code required. In Interface Builder set Line Break on UIButton to Word Wrap. Than you can insert multiple lines of title. Just hit Option + Return keys to make new line.
You will also need to add this to the User Defined Runtime Attribute in Interface Builder:
titleLabel.textAlignment Number [1]
It's that simple. Hope it helps...
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
[button setTitle: #"Line1\nLine2" forState: UIControlStateNormal];
To avoid completely the need to edit code, and thus the need to subclass your view, in Xcode5 and greater you can follow Borut Tomazin suggestion:
In Interface Builder (or storyboard) set Line Break to
Word Wrap. Than you can insert multiple lines of title. Just hit
Option + Return keys to make new line.
and then, in the User Defined Runtime Attributes you can add
Key path: titleLabel.textAlignment
Type: Number
Value: 1
Note: this may be not completely "future proof" since we are translating the UITextAlignmentCenter constant into its numerical value (and that constant may change as new iOS versions are released), but it seems safe in the near future.
You can modify the needed value directly from Storyboard.
Select the button, go to the identity inspector and add the following key-value pair in the "User defined runtime attributes" section:
I'm trying to change the background color of a button when it's selected and don't want to use an image.
[mBtn setBackgroundColor:[UIColor grayColor] forState:UIControlStateHighlighted];
Any thoughts?
I'm replying to this old thread because it pops up consistently in searches for a solution to this problem and I have seen no solution elsewhere. It is truly annoying that setTintColor only applies to the highlighted state of a UIButton. Six months ago, it was equally annoying that it applied only to iOS 5, but that will hopefully be less of an issue going forward. With that in mind, I've drawn upon and combined a number of community suggestions to composite a general purpose solution to tinting a group of buttons in their normal state.
The method below accepts an NSArray of UIButtons and a set of color specifications as input. It applies the color specifications to one button using setTintColor, renders the result to a UIImage, and applies that image as the background image of the entire set of buttons. This avoids the need to create discrete image files for button colors. Also, it does so using a stretchable image so that it may work with a collection of buttons of different sizes (though note that it assumes the default corner rounding factors of UIButton). I hope you'll find it useful for iOS 5 targets.
- (void) setColorOfButtons:(NSArray*)buttons red:(float)red green:(float)green blue:(float)blue alpha:(float)alpha {
if (buttons.count == 0) {
return;
}
// get the first button
NSEnumerator* buttonEnum = [buttons objectEnumerator];
UIButton* button = (UIButton*)[buttonEnum nextObject];
// set the button's highlight color
[button setTintColor:[UIColor colorWithRed:red/255.9999f green:green/255.9999f blue:blue/255.9999f alpha:alpha]];
// clear any existing background image
[button setBackgroundImage:nil forState:UIControlStateNormal];
// place the button into highlighted state with no title
BOOL wasHighlighted = button.highlighted;
NSString* savedTitle = [button titleForState:UIControlStateNormal];
[button setTitle:nil forState:UIControlStateNormal];
[button setHighlighted:YES];
// render the highlighted state of the button into an image
UIGraphicsBeginImageContext(button.layer.frame.size);
CGContextRef graphicsContext = UIGraphicsGetCurrentContext();
[button.layer renderInContext:graphicsContext];
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIImage* stretchableImage = [image stretchableImageWithLeftCapWidth:12 topCapHeight:0];
UIGraphicsEndImageContext();
// restore the button's state and title
[button setHighlighted:wasHighlighted];
[button setTitle:savedTitle forState:UIControlStateNormal];
// set background image of all buttons
do {
[button setBackgroundImage:stretchableImage forState:UIControlStateNormal];
} while (button = (UIButton*)[buttonEnum nextObject]);
}
[mBtn setTintColor:[UIColor grayColor]];
This only effects the highlighted state, so I believe that this is what you're looking for.
You can also set it from Interface Builder, from the Highlight Tint drop-down menu.
Just for people that will land here like I did when searching for changing background colors for highlighted state...
I ended up with an UIButton subclass that has a property for backgroundHighlightColor and tracks highlighting through KVO. Here's the link to GitHub: SOHighlightButton
You should be able to adapt it to any other scenario if you need more / other properties ot the UIButton to change if highlighted.
There is no method like this, setBackgroundColor: forState:
Check documentation. you need to use image.