Custom font in UISegmentedControl disable adjustsFontSizeToFitWidth - ios

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];

Related

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;
}

Change UIPickerView pickerView:viewForRow: attributes based on a certain condition

I am trying to change the text color in viewForRow based on a certain condition. When I press a button the view changes to a different color but I would also like to change the colour of the text in the picker. I use 'viewForRow' because I have a custom view.
//adds subcategories to the wheel
-(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, pickerView.frame.size.width, 44)];
label.backgroundColor = [UIColor clearColor];
if (!self.isBackgroundWhite)//Boolean that changes when the background changes
{
NSLog(#"Set white text");
label.textColor = [UIColor whiteColor];
}else{
label.textColor = [UIColor blackColor];
}
if (row == 1) {
label.text = [NSString stringWithFormat:#" %#",[self.servicesArray objectAtIndex:row]];
label.font = [UIFont fontWithName:#"HelveticaNeue-Bold" size:18];
}else{
label.text = [NSString stringWithFormat:#" -%#",[self.servicesArray objectAtIndex:row] ];
label.font = [UIFont fontWithName:kAppFont size:16];
}
return label;
}
EDIT: Thanks to #Rich I was able to spot my problem, I just need to call [self.pickerView reloadAllComponents];
If you only want to change the text color just use the other delegate method pickerView:attributedTitleForRow:forComponent:
- (NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *title;
UIFont *font;
if (row == 1) {
title = [NSString stringWithFormat:#" %#",[self.servicesArray objectAtIndex:row]];
font = [UIFont fontWithName:#"HelveticaNeue-Bold" size:18];
} else{
title = [NSString stringWithFormat:#" -%#",[self.servicesArray objectAtIndex:row] ];
font = [UIFont fontWithName:kAppFont size:16];
}
UIColor *textColor;
if (self.isBackgroundWhite) {
textColor = [UIColor blackColor];
} else {
NSLog(#"Set white text");
textColor = [UIColor whiteColor];
}
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.alignment = NSTextAlignmentLeft;
NSDictionary *attributes = #{NSForegroundColorAttributeName : textColor,
NSFontAttributeName : font,
NSParagraphStyleAttributeName : paragraphStyle};
return [[NSAttributedString alloc] initWithString:title attributes:attributes];
}
Also a note that you should call [self.pickerView reloadAllComponents]; when changing isBackgroundWhite. I would do this by overriding the setter for backgroundWhite and when the boolean value changes reload the picker view.
EDIT:
There appears to be a 'bug' (intentional or not) in iOS 7 (works fine on iOS 6) with setting the UIFont on an NSAttributedString returned from the pickerView:attributedTitleForRow:forComponent: method. So while the above works for the text color the font does not change. Luckily you can get around this with the code in the question. See this answer for more info.

iOS - Change text font for each segment in UISegmentController

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

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

Multiple lines of text in UISegmentedControl

is there an easy way, such that each item in my UISegmentedControl for instance,
has multiple lines of text?
Thanks.
ps. I've also checked there's no easy way to change the height of UISegmentedControl?
Say in Code? Changing the style to "Bar" does not suit me, and setFrame does not
seem to work in my case too... :((
pps. This is the approach I tried as recommended by Siba but still have some issues.
for (id segment in [segmentedControl subviews])
{
for (id label in [segment subviews])
{
if ([label isKindOfClass:[UILabel class]])
{
UILabel *label2 = label;
//hear u add any of delegate function to increase the height and other label functionality in this
[label2 setTextAlignment:UITextAlignmentCenter];
[label2 setFont:[UIFont boldSystemFontOfSize:12]];
//to adjust the label size manually with respect to text use below code
CGSize labelSize = CGSizeMake(100, 80);
CGSize theStringSize = [label2.text sizeWithFont:label2.font constrainedToSize:labelSize];
CGRect frame = label2.frame;
frame.size = theStringSize;
label2.lineBreakMode = UILineBreakModeWordWrap;
label2.numberOfLines = 0;
[label2 setText:#"text \n 10%"];
}
}
}
1.You can try the following.
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
Like one Done in This Answer :
UISegmentedControl text with multiple lines?
2.You can Take An ImageView in the back of Segmented Control with Same frame And Change images as per SelectedSegmentedIndex Like below.
But Don't forget to set Alpha of SegmentedControl to 0.05. At ViewDidLoad.
segment_Control.alpha=0.05;
The Coding will be Like this.
- (IBAction)segmented_Changed:(id)sender {
if (segmented_control.selectedSegmentIndex==0) {
segment_image.image=[UIImage imageNamed:#"tab_Act1.png"];
}else
if (segmented_control.selectedSegmentIndex==2) {
segment_image.image=[UIImage imageNamed:#"tab_Act3.png"];
}
else if (segmented_control.selectedSegmentIndex==1) {
segment_image.image=[UIImage imageNamed:#"tab_Act2.png"];
}
}
3.Also You Can try This :
for (id segment in [segmentedControl subviews])
{
for (id label in [segment subviews])
{
if ([label isKindOfClass:[UILabel class]])
{
//hear u add any of delegate function to increase the height and other label functionality in this
[label setTextAlignment:UITextAlignmentCenter];
[label setFont:[UIFont boldSystemFontOfSize:12]];
//to adjust the label size manually with respect to text use below code
CGSize labelSize = CGSizeMake(100, 80);
CGSize theStringSize = [label.text sizeWithFont:label.font constrainedToSize:labelSize];
CGRect frame = label.frame;
frame.size = theStringSize;
}
}
}
Source : Multiline Text On UIsegment Control

Resources