How can I make the text in one of the buttons in my UISegmentedControl span multiple lines?
7 Answers
Use UIAppearance to get things done. The below code snippet will work. Call this before creating your segment.
Objective-C
[[UILabel appearanceWhenContainedIn:[UISegmentedControl class], nil] setNumberOfLines:0];
Swift
UILabel.appearanceWhenContainedInInstancesOfClasses([UISegmentedControl.self]).numberOfLines = 0

- 2,011
- 7
- 29
- 40

- 742
- 5
- 9
-
2Since someone downvoted: It shouldn't work (numberOfLines isn't even a UIAppearance selector), but it actually works. Proof: http://i.stack.imgur.com/gE7Dv.png Problem seems to be that the label width seems to be taken solely from the first line. That's why I added these spaces in the code. – Matthias Bauch May 23 '15 at 09:31
-
@MatthiasBauch try removing the new line character – Saranya Sivanandham May 23 '15 at 09:34
-
Without the newline it wouldn't be a multi line label. ;) Thanks anyway, but I don't have that problem anymore, I solved it with the top-voted answer a while ago. Just wanted to explain that the downvote was not necessary. – Matthias Bauch May 23 '15 at 09:36
-
This API is available on iOS 9.0+. – Yaroslav Feb 03 '16 at 14:21
-
[[UILabel appearanceWhenContainedInInstancesOfClasses:@[[UISegmentedControl class]]] setNumberOfLines:0]; this code will work for iOS 12 – R. Mohan Jan 20 '19 at 10:07
-
Swift 5 (add in AppDelegate to get this to work for controls added in Storyboard): UILabel.appearance(whenContainedInInstancesOf: [UISegmentedControl.self]).numberOfLines = 0 – D. Pratt May 20 '19 at 15:46
I did it this way:
- create a multiline UILabel
- fill the label with N lines of text
- convert the label into an UIImage
- set the image as a segments content
This works smooth on iOS 4, 5, 6
and iOS 7 (just remove the text shadow)
MultiLineSegmentedControl - header file
//
// MultiLineSegmentedControl.h
//
// Created by Jens Kreiensiek on 20.07.11.
// Copyright 2011 SoButz. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MultiLineSegmentedControl : UISegmentedControl
- (void)setMultilineTitle:(NSString *)title forSegmentAtIndex:(NSUInteger)segment;
@end
MultiLineSegmentedControl - implementation file
//
// MultiLineSegmentedControl.m
//
// Created by Jens Kreiensiek on 20.07.11.
// Copyright 2011 SoButz. All rights reserved.
//
#import "MultiLineSegmentedControl.h"
#import "UIView+LayerShot.h"
@interface MultiLineSegmentedControl()
@property (nonatomic, retain) UILabel *theLabel;
@end
@implementation MultiLineSegmentedControl
@synthesize theLabel;
- (void)dealloc
{
self.theLabel = nil;
[super dealloc];
}
- (UILabel *)theLabel
{
if (!self->theLabel) {
self->theLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self->theLabel.textColor = [UIColor whiteColor];
self->theLabel.backgroundColor = [UIColor clearColor];
self->theLabel.font = [UIFont boldSystemFontOfSize:13];
self->theLabel.textAlignment = UITextAlignmentCenter;
self->theLabel.lineBreakMode = UILineBreakModeWordWrap;
self->theLabel.shadowColor = [UIColor darkGrayColor];
self->theLabel.numberOfLines = 0;
}
return self->theLabel;
}
- (void)setMultilineTitle:(NSString *)title forSegmentAtIndex:(NSUInteger)segment
{
self.theLabel.text = title;
[self.theLabel sizeToFit];
[self setImage:self.theLabel.imageFromLayer forSegmentAtIndex:segment];
}
@end
UIView+LayerShot - header file
//
// UIView+LayerShot.h
//
// Created by Jens Kreiensiek on 29.06.12.
// Copyright (c) 2012 SoButz. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIView (LayerShot)
- (UIImage *)imageFromLayer;
@end
UIView+LayerShot - implementation file
//
// UIView+LayerShot.m
//
// Created by Jens Kreiensiek on 29.06.12.
// Copyright (c) 2012 SoButz. All rights reserved.
//
#import "UIView+LayerShot.h"
#import <QuartzCore/QuartzCore.h>
@implementation UIView (LayerShot)
- (UIImage *)imageFromLayer
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
@end
Use it just like a normal UISegmentedControl:
...
MultiLineSegmentedControl *segment = [[MultiLineSegmentedControl alloc]
initWithItems:[NSArray arrayWithObjects:@"A", @"B", nil]];
segment.segmentedControlStyle = UISegmentedControlStyleBar;
segment.frame = CGRectMake(0, 0, 200, segment.frame.size.height * 1.5);
[segment setMultilineTitle:@"Title A\nSubtitle A" forSegmentAtIndex:0];
[segment setMultilineTitle:@"Title B\nSubtitle B" forSegmentAtIndex:1];
[self.view addSubview:segment];
[segment release];
...

- 909
- 14
- 20
-
@SoButz: I can't see any subtitle. I created subclass of UISegmentedControl & added above code. Create a MultiLineSegmentedControl in viewDidLoad of my view controller. But its not showing subtitle. I have #import "MultiLineSegmentedControl.h". Can you help me ? Thanks – iOSAppDev Dec 06 '12 at 07:50
-
iOSAppDev, I have updated the example to the method I'm using now on iOS 6. Give it a try... – Jenson Dec 12 '12 at 18:43
-
1@SoButz: I have Segment names as @"All", @"My\nFriends",@"Closing\nSoon", @"Nearby". But still its not showing correctly. [Have a look](http://s8.postimage.org/hb724i105/SEGMENTED.png) Whats going wrong here ? – iOSAppDev Jan 16 '13 at 09:35
-
Swift 3+ syntax based on answer by @Saranya Sivanandham
UILabel.appearance(whenContainedInInstancesOf: [UISegmentedControl.self]).numberOfLines = 0

- 3,209
- 1
- 34
- 40
-
3it is not working for me :( did anyone try this and had the expected result ?? – Niib Fouda Mar 29 '18 at 10:41
-
@Venkatesh Chejaria. Yes, adding this line in your App Delegate or any other class would work for UISegmentedControl that's added either programmatically or from Storyboard. – Maverick Jan 19 '19 at 13:21
The approach above is better, but for the sake of having an alternative, you can do something like:
for(UIView *subview in segmentedControl.subviews) {
if([NSStringFromClass(subview.class) isEqualToString:@"UISegment"]) {
for(UIView *segmentSubview in subview.subviews) {
if([NSStringFromClass(segmentSubview.class) isEqualToString:@"UISegmentLabel"]) {
UILabel *label = (id)segmentSubview;
label.numberOfLines = 2;
label.text = @"Hello\nWorld";
CGRect frame = label.frame;
frame.size = label.superview.frame.size;
label.frame = frame;
}
}
}
}

- 31,411
- 46
- 180
- 303
-
Hello @moby, thanks for your alternative. if I want to give a different name for my label text, how can I do it in your alternative? – benhi Dec 09 '14 at 10:07
Years later...
for segment in segmented.subviews{
for label in segment.subviews{
if let labels = label as? UILabel{
labels.numberOfLines = 2
}
}
}

- 274
- 2
- 11
For iOS 12, the below code will work like charm
[[UILabel appearanceWhenContainedInInstancesOfClasses:@[[UISegmentedControl class]]] setNumberOfLines:0];

- 2,182
- 17
- 30
I have a storyboard with UISegmentedControl in some views. I drag those controls to my class as @IBOutlet
. Here are some codes to make labels in segmented controls multiple lines:
class MyViewController: UIViewController {
...
@IBOutlet weak var segmentedCtrl: UISegmentedControl!
{
didSet {
// localize strings
let text1 = ... // localizedString
...
segmentedCtrl.setTitle(text1, forSegmentAt: 0)
...
// Following code making multiple lines happen!
UILabel.appearance(whenContainedInInstancesOf:
[UISegmentedControl.self]).numberOfLines = 0
}
...
}

- 37,408
- 63
- 148
- 190