iOS - Change text font for each segment in UISegmentController - ios

I got a UISegmentedControl called mySegmentedControl
#property (nonatomic) IBOutlet UISegmentedControl *mySegmentedControl;
with 3 segments, and I would change text font for each segment.. Is possible?

Yes you can ----- Try this
for(uint i=0;i<[mySegmentedControl subviews].count;i++)
{
for(UIView *view in [[[mySegmentedControl subviews] objectAtIndex:i] subviews])
{
if([view isKindOfClass:[UILabel class]])
{
if(i==0) // set First segment font
[(UILabel*)view setFont:[UIFont fontWithName:#"HelveticaNeue-Light" size:27]];
if(i==1) // set Second segment font
[(UILabel*)view setFont:[UIFont fontWithName:#"HelveticaNeue-Light" size:17]];
if(i==2) // set Third segment font
[(UILabel*)view setFont:[UIFont fontWithName:#"HelveticaNeue-Light" size:7]];
}
}
}

You can use any images instead of text. This will give you flexible customization for appearance.
NSArray *segemtImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"1st.png"],[UIImage imageNamed:#"2nd.png"],[UIImage imageNamed:#"3rd.png"], nil];
UISegmentedControl *segmentControl = [[UISegmentedControl alloc] initWithItems:segemtImages];

I don't think that is possible. Your only options are either use a custom open source implementation, or set a custom image with the text for each segment.

I modify #Anand Natan 's code:
In storyboard set the first label "1111111111111" is to change it default width. Because change the label don't change segmentcontroll size.
for(uint i=0;i<[_menuBarTop subviews].count;i++){
for(uint j=0;j<[[[[_menuBarTop subviews] objectAtIndex:i] subviews]count];j++){
UIView* view = [[[_menuBarTop subviews] objectAtIndex:i] subviews][j];
if([view isKindOfClass:[UILabel class]]){
UILabel* label = (UILabel*)view;
if([label.text isEqualToString:#"1111111111111"]){
label.text = LANGLOC(#"videolist_category_choosen");
}else if([label.text isEqualToString:#"2"]){
label.text = LANGLOC(#"videolist_category_followed");
}
break;
}
}
}

NSDictionary *textAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIFont boldSystemFontOfSize:12], NSFontAttributeName, nil];
[_sgmntStatusUI setTitleTextAttributes:textAttributes forState:UIControlStateNormal];
for ios7 later varsions

Related

Custom font in UISegmentedControl disable adjustsFontSizeToFitWidth

I have set a custom font for my UISegmentedControl, but it seems to disable the default autoAdjustFontSizeToFitWidth parameter.
Before:
After:
Here is the code I apply to set my custom font:
UISegmentedControl *segmentedControl = (UISegmentedControl *)subview;
UIFont *font = [UIFont fontWithName:DEFAULT_FONT size:DEFAULT_FONT_SIZE];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
[segmentedControl setTitleTextAttributes:attributes forState:UIControlStateNormal];
Is there a way to preserve it? Many thanks.
EDIT: I would like to avoid
segmentedControl.apportionsSegmentWidthsByContent = YES;
if possible to always have same width for every segment.
I just had to do this. You can search through the subviews of the segment control and set the properties.
+ (void) setAdjustsFontForWidth:(UIView *) view {
NSArray * subvies = view.subviews;
for(UIView * view in subvies) {
if([view isKindOfClass:[UILabel class]]) {
UILabel * label = (UILabel *)view;
NSLog(#"label found: %#", label.text);
label.adjustsFontSizeToFitWidth = TRUE;
label.minimumScaleFactor = .1;
} else {
[self setAdjustsFontForWidth:view];
}
}
}
Call it with:
[Utils setAdjustsFontForWidth:mySegmentControl];

Scale UISegmentedControl labels based on width of control

This seems like a no brainer, but I cannot find any way to do this. Basically what I have is a UISegmentedControl with two localized labels using NSLocalizedString. I have set the font size and everything looks great in English and a few other languages. But, in Japanese and other languages the characters are larger and cause the label to be truncated.
self.segmentedControl = [[UISegmentedControl alloc] initWithItems:
[NSArray arrayWithObjects:
NSLocalizedString(#"Miles", nil).uppercaseString,
NSLocalizedString(#"Kilometers", nil).uppercaseString,
nil]];
self.segmentedControl.apportionsSegmentWidthsByContent = YES;
self.segmentedControl.selectedSegmentIndex = self.metric ? 1 : 0;
[self.segmentedControl addTarget:self action:#selector(changeMetric:) forControlEvents:UIControlEventValueChanged];
self.segmentedControl.frame = CGRectMake(8, middleHolder.frame.size.height/2+60, progressWidth, 30);
self.segmentedControl.center = CGPointMake(self.view.center.x, self.segmentedControl.center.y);
[self.segmentedControl setTitleTextAttributes:#{
NSForegroundColorAttributeName: [UIColor whiteColor],
NSFontAttributeName: [UIFont fontWithName:#"HelveticaNeue-UltraLight" size:36]
} forState:UIControlStateSelected];
[self.segmentedControl setTitleTextAttributes:#{
NSForegroundColorAttributeName: [[UIColor whiteColor] colorWithAlphaComponent:0.3],
NSFontAttributeName: [UIFont fontWithName:#"HelveticaNeue-UltraLight" size:36]
} forState:UIControlStateNormal];
self.segmentedControl.tintColor = [UIColor clearColor];
self.segmentedControl.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[middleHolder addSubview:self.segmentedControl];
Is there any way to scale the font size of the label depending on the label width? I realize that these are not normal UILabel's, so there is no adjustsFontSizeToFitWidth property.
I'm tackling with the same issue. Here is my solution (a bit rough around the edges):
I subclass the segmented control and then in my subclass, do the following. Hope this helps! (Tested on iOS 7 and 8)
+ (void)setSublabelScale:(UIView *)view {
for (id subview in view.subviews) {
if ([subview isKindOfClass:[UILabel class]]) {
[subview setMinimumScaleFactor:0.5];
[subview setAdjustsFontSizeToFitWidth:YES];
} else {
[MYSegmentedControl setSublabelScale:subview];
}
}
}
- (void)layoutSubviews {
[super layoutSubviews];
[MYSegmentedControl setSublabelScale:self];
}
I found out that NSAttributedString has a size property to it, that will allow me to know how wide the text is for every local. So, I can just do something like:
CGFloat fontSize = 36;
NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:NSLocalizedString(#"Kilometers", nil).uppercaseString attributes:#{NSFontAttributeName: [UIFont fontWithName:#"HelveticaNeue-UltraLight" size:fontSize]}];
if (attributedString.size.width > 200) {
fontSize = 30;
}

Two lines of text in a UISegmentedControl

Try as I might, I can't solve a UISegmentedControl bug for an iOS7 iPhone app.
When I create the segmented control, I use this code:
NSArray *segmentedControlItemArray = [NSArray arrayWithObjects: #"Nominal:\n27 inch", #"Actual:\n700c x 23mm", #"Actual:\n700c x 20mm", nil];
_wheelDiameterSegmentedControl = [[UISegmentedControl alloc] initWithItems:segmentedControlItemArray];
_wheelDiameterSegmentedControl.frame = CGRectMake(0, 102, 290, 50);
_wheelDiameterSegmentedControl.selectedSegmentIndex = 0;
_wheelDiameterSegmentedControl.tintColor = [UIColor colorWithRed:0.35 green:0.4 blue:0.9 alpha:1.0];
for (id segment in [_wheelDiameterSegmentedControl subviews]) {
for (id label in [segment subviews]) {
if ([label isKindOfClass:[UILabel class]]) {
UILabel *titleLabel = (UILabel *) label;
titleLabel.numberOfLines = 0;
}
}
}
[_wheelDiameterSegmentedControl addTarget:self
action:#selector(pickOne:)
forControlEvents:UIControlEventValueChanged];
[_wheelDiameterMenuContainer addSubview:_wheelDiameterSegmentedControl];
Sadly, I can't post images, or I would show you a picture of exactly the control I want: each of the segments in the UISegmented Control has two lines of text, with a line break exactly where I asked for it.
On rotation, though, I'd like to keep the segmented control full-width, and the line breaks look silly in segments that wide. So, in willAnimateRotationToInterfaceOrientation, I've included the following code, with no line breaks in the strings:
[_wheelDiameterSegmentedControl setFrame:CGRectMake(0, 102, 450, 50)];
[_wheelDiameterSegmentedControl setTitle:#"Nominal: 27 inch" forSegmentAtIndex:0];
[_wheelDiameterSegmentedControl setTitle:#"Actual: 700c x 23mm" forSegmentAtIndex:1];
[_wheelDiameterSegmentedControl setTitle:#"Actual: 700c x 20mm" forSegmentAtIndex:2];
And once again, if I could insert an image, I would show you an image of exactly what I want: a wide UISegmented Control with no line breaks in the labels (1 line of text per label).
Here's where I run in to trouble. My choices, when I rotate back to portrait, seem to be:
1 line of label text, truncated, with the format
"Actual: 7..."
when I just reset the size of the UISegmentedControl using
[_wheelDiameterSegmentedControl setFrame:CGRectMake(0, 102, 290, 50)];
2 lines of label text, truncated, with the format
"Actual:
700c x ..."
when I reset the size and also reset the string values and rerun the loop of code that sets the label's numberOfLines to 2, using
NSArray *segmentedControlItemArray = [NSArray arrayWithObjects: #"Nominal:\n27 inch", #"Actual:\n700c x 23mm", #"Actual:\n700c x 20mm", nil];
[_wheelDiameterSegmentedControl setTitle:[segmentedControlItemArray objectAtIndex:0] forSegmentAtIndex:0];
[_wheelDiameterSegmentedControl setTitle:[segmentedControlItemArray objectAtIndex:1] forSegmentAtIndex:1];
[_wheelDiameterSegmentedControl setTitle:[segmentedControlItemArray objectAtIndex:2] forSegmentAtIndex:2];
for (id segment in [_wheelDiameterSegmentedControl subviews]) {
for (id label in [segment subviews]) {
if ([label isKindOfClass:[UILabel class]]) {
UILabel *titleLabel = (UILabel *) label;
titleLabel.numberOfLines = 2;
}
}
}
[_wheelDiameterSegmentedControl setFrame:CGRectMake(0, 102, 290, 50)];
3 lines of label text, with the format
"Actual:
700c x
20mm"
which is what I get when I replace the forced numberOfLines = 2 above with the numberOfLines = 0 that worked when I set up the UISegmentedControl in the first place.
What I'd like is what I get when I create the control, which is
"Actual:
700c x 20mm"
But no matter what I've tried (putting the string and numberOfLines code into willRotateToInterfaceOrientation or didRotateFromInterfaceOrientation; re-setting the frame of the UISegmentedControl before changing the text; re-setting the frame after changing the text...), I can't get my nice, neat, two-line label back. What am I missing here?
Aha! Something about how the OS is handling the size of the label when it rotates is different from how it handles the label when it's created. So I forced the size of the frame of the label, using
for (id segment in [_wheelDiameterSegmentedControl subviews]) {
for (id label in [segment subviews]) {
if ([label isKindOfClass:[UILabel class]]) {
UILabel *titleLabel = (UILabel *) label;
//inserting line here, to make the frame behave nicely:
//
titleLabel.frame = CGRectMake(0, 0, 97, 50);
//
//continuing as before
titleLabel.numberOfLines = 0;
}
}
}
and now it displays exactly as I want/expect. Huzzah!
If you're just trying to get two (or more) lines of text in your UISegmentedControl. Using Herzian's amazing technology! Here's just another code example, that may help people...
self.yourSlider .. set the height manually (can't easily do it in XIB)
// now use amazing Herzian technology...
for (id segment in [self.yourSlider subviews])
for (id label in [segment subviews])
{
if ([label isKindOfClass:[UILabel class]])
{
UILabel *titleLabel = (UILabel *) label;
titleLabel .. set the width to say 80, per your layout;
(the width us typically too low)
titleLabel.numberOfLines = 0;
}
}
thank you so much, again.
working code in ios 7 :
I have a segment controller with four segments and I need it in 2 lines for text. So I have added UILabel as a subview in segment of UISegmentedControl and it is working good. I have tried all other ways but in ios 7 and ios 8 it is working good right now.
for(int k =0;k<4;k++)
{
NSString *text = #"title name";
UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(10,2, (self.segmentcontroll.frame.size.width/4), 34);
label.font = [UIFont fontWithName:#"HelveticaNeue" size:12.0];
label.textColor = [UIColor whiteColor];
label.text = text;
label.numberOfLines = 0;
label.textAlignment = NSTextAlignmentCenter;
[label sizeToFit];
[[[self.segmentcontroll subviews] objectAtIndex:k] addSubview:label];
}
And Herzian's solution as a category if anyone wants it. Remember to call it in VWA instead of VDL so it happens after autosizing / rotation
#import "UISegmentedControl+MultiLine.h"
#implementation UISegmentedControl (MultiLine)
-(void)setupMultiLine
{
self.frame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
self.frame.size.height*1.6);
for (id segment in self.subviews)
{
for (id label in [segment subviews])
{
if ([label isKindOfClass:[UILabel class]])
{
UILabel *titleLabel = (UILabel*) label;
titleLabel.frame = CGRectMake(0,
0,
titleLabel.frame.size.width,
titleLabel.frame.size.height*1.6);
titleLabel.numberOfLines = 0;
}
}
}
}
#end

How can I set the font for the selected element in a UISegmentedControl?

I'm trying to use different fonts for the selected and un-selected segments in a UISegmentedControl. I can set the font for the normal segments, but I can't seem to set the font for the selected segment. Here's my code:
NSDictionary *attributes = [NSDictionary dictionaryWithObject:
[UIFont fontWithName:#"Verdana-Bold"
size:[UIFont buttonFontSize]]
forKey:UITextAttributeFont];
[playerNumber setTitleTextAttributes:attributes
forState:UIControlStateHighlighted];
If I change to UIControlStateNormal, all the segments are styled. However, I just want to style the highlighted/selected segment. (UIControlStateSelected doesn't work either.)
(There are a few similar StackOverflow questions, but I couldn't find an answer that solved my issue.)
What am I doing wrong or can't it be done at all?
Have you tried setting the font on segment select, rather than trying to predefine the selectedState font to be used for all segments? Something like the following (untested):
int segmentIndex = self.mySegmentedControl.selectedSegmentIndex;
if (segmentIndex == 0)
{
[self.mySegmentedControl setFont:[UIFont boldSystemFontOfSize:12] forSegmentAtIndex:0];
[self.mySegmentedControl setFont:[UIFont systemFontOfSize:10] forSegmentAtIndex:1];
}
else if (segmentIndex == 1)
{
[self.mySegmentedControl setFont:[UIFont systemFontOfSize:10] forSegmentAtIndex:0];
[self.mySegmentedControl setFont:[UIFont boldSystemFontOfSize:12] forSegmentAtIndex:1];
}
I do something along these lines in one of my apps now, but it is using images for the segments.
I met this issue today, I believe this is an iOS's bug.
Here is my hack.
#interface TFSegmentedControl : UISegmentedControl
#end
#import "TFSegmentedControl.h"
#implementation TFSegmentedControl
{
BOOL layoutedOnce;
}
- (void)updateSelectedStyle
{
for (UIView *view in self.subviews) {
BOOL selected = [[view valueForKey:#"selected"] boolValue];
for (UILabel *label in view.subviews) {
if ([label isKindOfClass:[UILabel class]]) {
UIFont *font = [self titleTextAttributesForState:UIControlStateNormal][UITextAttributeFont];
if (selected) {
UIFont *_font = [self titleTextAttributesForState:UIControlStateSelected][UITextAttributeFont];
if (_font) font = _font;
}
if (font != label.font) {
label.font = font;
CGRect frame = label.frame;
frame.size = [label.text sizeWithFont:font];
label.frame = frame;
}
}
}
}
}
- (void)sendActionsForControlEvents:(UIControlEvents)controlEvents
{
[self updateSelectedStyle];
[super sendActionsForControlEvents:controlEvents];
}
- (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex
{
[super setSelectedSegmentIndex:selectedSegmentIndex];
[self updateSelectedStyle];
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (!layoutedOnce) {
layoutedOnce = YES;
[self updateSelectedStyle];
}
}
#end

set the font of UItextview

I have multiple textviews in my uiview I need to set the font size of this textviews, so I used the following code but it didn't change the font size,
for (UIView *subview in self.view.subviews) {
if ([subview isKindOfClass:[UITextView class]]) {
((UITextView *)subview).font = [UIFont fontWithName:#"Helvetica" size:12];
}
}
As #jrturton says, perhaps your text views are subviews of a subview, then some kind of recursive code is needed. For example:
-(void) setNewFontToTextViews:(UIView*) theView {
if([[theView subviews] count])
for( UIView * subView in [theView subviews])
[self setNewFontToTextViews:subView] ;
else if([theView isKindOfClass:[UITextView class]])
[(UITextView*)theView setFont:[UIFont fontWithName:#"Helvetica" size:12]];
}

Resources