How to resize text (font) to fit in UISegment of UISegmentedControl?
Asked Answered
A

5

9

Is there any way to reduce font size that can be fit in single segment of UISegmentedControl ?

Have tried many thing something like,

[[UILabel appearanceWhenContainedIn:[UISegmentedControl class], nil] adjustsFontSizeToFitWidth];

[[UILabel appearanceWhenContainedIn:[UISegmentedControl class], nil] setMinimumScaleFactor:0.5];

AND

 NSArray *arr = segment.subviews;  // segment is UISegmentedControl object

for (int i = 0; i < arr.count; i++) {

    UIView *aSegment = [arr objectAtIndex:i];

    for (UILabel *label in aSegment.subviews) {

        if ([label isKindOfClass:[UILabel class]]) {

            UILabel *myLabel = (UILabel *)label;

            [myLabel setNumberOfLines:0];

            label.numberOfLines = 0;
            label.adjustsFontSizeToFitWidth = YES;
            label.minimumScaleFactor = 0.5;
        }



    }
}

able to set number of lines of label of segment like,

  [[UILabel appearanceWhenContainedIn:[UISegmentedControl class], nil] setNumberOfLines:0];

Can set single segment size as per content like,

  segment.apportionsSegmentWidthsByContent = YES;

but every segment has different size in this case.

I want to keep same size of every segment and want to reduce font size that can be fit in UISegmentLabel (label) of UISegmentedControl something like minimumscalefactor or minimumfontsize or adjustsFontSizeToFitWidth. These properties is not working for label when contains in UISegmentedControl.

If any one can help to achieve this, it will be appreciated!!

Thanks in advance!!

Appanage answered 22/7, 2016 at 7:6 Comment(2)
see this #26453797 and see this #22165671 you get some ideaChronology
@Chronology : thanks for links!! actually i was making little mistake and now solved it!Appanage
A
8

I found the issue, Actually it was my mistake!!! I was setting numberOfLines,adjustsFontSizeToFitWidth,minimumScaleFactor and TitleTextAttributes toghether. If we set titleTextAttribute then minimumScaleFactor can't work.

Update : (As asked by @HawkEye1194 in comment of another answer)

I have end up with below solution,

 //this will allow multiple lines in label contained by every segment in segmentedcontroller

[[UILabel appearanceWhenContainedIn:[UISegmentedControl class], nil] setNumberOfLines:0];


UISegmentedControl *segment = [[UISegmentedControl alloc]initWithItems:option];
segment.frame = CGRectMake(20, 50, self.view.frame.size.width - 40, 50);
segment.tintColor = [UIColor grayColor];
segment.selectedSegmentIndex = 0;
segment.backgroundColor = [UIColor whiteColor];
segment.tag = segmentedControllerBaseTag;


[segment addTarget:self action:@selector(segmentChanged:) forControlEvents:UIControlEventValueChanged];

[segment setTitleTextAttributes:@{NSFontAttributeName :[UIFont fontWithName:@"HelveticaNeue" size:17.0], NSForegroundColorAttributeName : [UIColor darkGrayColor] } forState:UIControlStateNormal];
[segment setTitleTextAttributes:@{NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue" size:17.0],NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateSelected];

If your not setting title textattribute as above then you can use below code

// ********** if titletextattributes are not set then below method works ***********

   for(uint i=0;i<[segment subviews].count;i++)
   {
    for(UIView *view in [[[segment subviews] objectAtIndex:i] subviews])
    {
        if([view isKindOfClass:[UILabel class]])
        {

            [(UILabel*)view setNumberOfLines:0];
            [(UILabel*)view setAdjustsFontSizeToFitWidth:YES];
            [(UILabel*)view setMinimumScaleFactor:0.7];


        }
    }
}

You can adjust single segment's size as per it's content by below code,

 //*************** adjust single segment size as per content

 segment.apportionsSegmentWidthsByContent = YES;
Appanage answered 22/7, 2016 at 10:55 Comment(0)
I
3

Try this, I hope this will help you and you will get an idea how this works-

I have a UISegmentedControl i.e. _userProfileSagmentOutlet having three segments. Here is sample code-

CGFloat fontSize = 15;

[_userProfileSagmentOutlet setTitleTextAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Roboto-medium" size:fontSize],
                                                    NSForegroundColorAttributeName:[UIColor whiteColor]}
                                         forState:UIControlStateSelected];

[_userProfileSagmentOutlet setTitleTextAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Roboto-medium" size:fontSize],
                                                    NSForegroundColorAttributeName:[UIColor whiteColor]}
                                         forState:UIControlStateNormal];

this is the previous code which truncate tail of title like below image-

enter image description here

here is the main logic which fit each title in segments with same font size-

CGFloat fontSize = 15;

NSAttributedString* firstTitle = [[NSAttributedString alloc] initWithString:@"Membership History" attributes:@{NSFontAttributeName: [UIFont fontWithName:@"Roboto-medium" size:fontSize]}];

NSAttributedString* secondTitle = [[NSAttributedString alloc] initWithString:@"Event History" attributes:@{NSFontAttributeName: [UIFont fontWithName:@"Roboto-medium" size:fontSize]}];

NSAttributedString* thirdTitle = [[NSAttributedString alloc] initWithString:@"Booked Classes" attributes:@{NSFontAttributeName: [UIFont fontWithName:@"Roboto-medium" size:fontSize]}];


float maxW=MAX(MAX(firstTitle.size.width, secondTitle.size.width), thirdTitle.size.width);

while (maxW > _userProfileSagmentOutlet.subviews[0].frame.size.width) {

    fontSize--;

    firstTitle = [[NSAttributedString alloc] initWithString:@"Membership History" attributes:@{NSFontAttributeName: [UIFont fontWithName:@"Roboto-medium" size:fontSize]}];

    secondTitle = [[NSAttributedString alloc] initWithString:@"Event History" attributes:@{NSFontAttributeName: [UIFont fontWithName:@"Roboto-medium" size:fontSize]}];

    thirdTitle = [[NSAttributedString alloc] initWithString:@"Booked Classes" attributes:@{NSFontAttributeName: [UIFont fontWithName:@"Roboto-medium" size:fontSize]}];

    maxW=MAX(MAX(firstTitle.size.width, secondTitle.size.width), thirdTitle.size.width);


}
[_userProfileSagmentOutlet setTitleTextAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Roboto-medium" size:fontSize],
                                                    NSForegroundColorAttributeName:[UIColor whiteColor]}
                                         forState:UIControlStateSelected];

[_userProfileSagmentOutlet setTitleTextAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Roboto-medium" size:fontSize],
                                                    NSForegroundColorAttributeName:[UIColor whiteColor]}
                                         forState:UIControlStateNormal];

after using this code image look like this(same font size and text fit to segment and works fine)-

enter image description here

Here is Swift extension if someone needed-

    var fontSize:CGFloat = 15.0;

    var firstTitle = NSMutableAttributedString.init(string: "Membership History", attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)])

    var secondTitle = NSMutableAttributedString.init(string: "Events History" ,attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)]);

    var thirdTitle = NSMutableAttributedString.init(string: "Booked Classes" ,attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)]);

    var maxW:CGFloat = max(max(firstTitle.size().width, secondTitle.size().width), thirdTitle.size().width);

    while (maxW > userProfileSagmentOutlet.subviews[0].frame.size.width) {

        fontSize--;

         firstTitle = NSMutableAttributedString.init(string: "Membership History", attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)])

         secondTitle = NSMutableAttributedString.init(string: "Events History" ,attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)]);

         thirdTitle = NSMutableAttributedString.init(string: "Booked Classes" ,attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)]);

         maxW = max(max(firstTitle.size().width, secondTitle.size().width), thirdTitle.size().width);

    }
    userProfileSagmentOutlet.setTitleTextAttributes([NSFontAttributeName: UIFont.systemFontOfSize(fontSize),NSForegroundColorAttributeName:UIColor.whiteColor()], forState:UIControlState.Normal)

    userProfileSagmentOutlet.setTitleTextAttributes([NSFontAttributeName: UIFont.systemFontOfSize(fontSize),NSForegroundColorAttributeName:UIColor.whiteColor()], forState:UIControlState.Selected)
Integument answered 22/7, 2016 at 8:37 Comment(2)
this is the good approach but not suitable in my case, because in my cases number of segment(title) is not fix, It is dynamic some time it is 2 where some time it can be 5 or more etc. But your approach is quite good. +1 for that!Appanage
@Lion Thanks..Happy to hear that your problem has been solved.Integument
B
3

SWIFT 4

allow multiple lines in label

if #available(iOS 9.0, *) {
    UILabel.appearance(whenContainedInInstancesOf: [UISegmentedControl.self]).numberOfLines = 0
}
Booth answered 14/7, 2018 at 9:59 Comment(0)
H
1

The most simple solution in modern Swift would be

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
        
    _ = Your_UISegmentControl.subviews.compactMap { $0.subviews.compactMap {
        ($0 as? UILabel)?.adjustsFontSizeToFitWidth = true
        ($0 as? UILabel)?.minimumScaleFactor = 0.5
    }}
}
Hollie answered 8/8, 2021 at 14:46 Comment(0)
V
0

I ran this in the view controller, and called it after viewDidAppear

func autoshrinkSegmentFontSize() {
    for subview in segments.subviews {
        for label in subview.subviews {
            if let myLabel = subview as? UILabel {
                myLabel.adjustsFontSizeToFitWidth = true
                myLabel.minimumScaleFactor = 0.5
            }
        }
    }
}
Voight answered 17/2, 2021 at 6:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.