Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I calculate correct widths for UISegmentedControl segments?

I'm trying to use a UISegmentedControl but having trouble calculating the width of the segments. The control makes the segments all the same width which doesn't work for some titles, like this one:

http://morrisphotoart.com/tmp/Screenshot2011-07-13_21.17.33.png

I can write code to calculate the segment width if I knew which font and call the setWidth:forSegmentAtIndex: method but how can I get the font? Or is there another way?

The left and middle segment's titles are not fixed so I can't hardcode the widths.

like image 594
progrmr Avatar asked Jul 14 '11 04:07

progrmr


3 Answers

If you can support iOS 5 and later then you can use the property apportionsSegmentWidthsByContent and set it to YES.

From the iOS 5 docs:

apportionsSegmentWidthsByContent

Indicates whether the control attempts to adjust segment widths based on their content widths.

@property(nonatomic) BOOL apportionsSegmentWidthsByContent

Discussion

If the value of this property is YES, for segments whose width value is 0, the control attempts to adjust segment widths based on their content widths.

like image 67
Camsoft Avatar answered Oct 18 '22 17:10

Camsoft


EDIT: an easier option might be to use the iOS 5 property apportionsSegmentWidthsByContent as mentioned in @Camsoft's answer here


Well, I ended up getting the UIFont from poking thru the subviews (which could break in a future iOS). Being a modular/reuse aficianado, I wrote this routine to do it and then to distribute the space so that the segments in the control are evenly spaced for the titles.

-(void)resizeSegmentsToFitTitles:(UISegmentedControl*)segCtrl {
    CGFloat totalWidths = 0;    // total of all label text widths
    NSUInteger nSegments = segCtrl.subviews.count;    
    UIView* aSegment = [segCtrl.subviews objectAtIndex:0];
    UIFont* theFont = nil;

    for (UILabel* aLabel in aSegment.subviews) {
        if ([aLabel isKindOfClass:[UILabel class]]) {
            theFont = aLabel.font;
            break;
        }
    }

    // calculate width that all the title text takes up
    for (NSUInteger i=0; i < nSegments; i++) {
        CGFloat textWidth = [[segCtrl titleForSegmentAtIndex:i] sizeWithFont:theFont].width;
        totalWidths += textWidth;
    }

    // width not used up by text, its the space between labels
    CGFloat spaceWidth = segCtrl.bounds.size.width - totalWidths;   

    // now resize the segments to accomodate text size plus 
    // give them each an equal part of the leftover space
    for (NSUInteger i=0; i < nSegments; i++) {
        // size for label width plus an equal share of the space
        CGFloat textWidth = [[segCtrl titleForSegmentAtIndex:i] sizeWithFont:theFont].width;
        // roundf??  the control leaves 1 pixel gap between segments if width 
        // is not an integer value, the roundf fixes this
        CGFloat segWidth = roundf(textWidth + (spaceWidth / nSegments));    
        [segCtrl setWidth:segWidth forSegmentAtIndex:i];
    }
}
like image 35
progrmr Avatar answered Oct 18 '22 18:10

progrmr


NSArray *itemArray = [NSArray arrayWithObjects: @"Title1", @"Title2", @"Titl3", @"Title4",nil];
segmentedControl = [[UISegmentedControl alloc] initWithItems:itemArray];
segmentedControl.frame = CGRectMake(0, 0, 310, 35);
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
segmentedControl.selectedSegmentIndex = 0;
[segmentedControl addTarget:self action:@selector(pickOne:) forControlEvents:UIControlEventValueChanged];   
segmentedControl.tintColor=[UIColor grayColor];

for (id segment in [segmentedControl subviews]) 
{
    for (id label in [segment subviews]) 
    {
        if ([label isKindOfClass:[UILabel class]])
        {

            [label setTextAlignment:UITextAlignmentCenter];
            [label setFont:[UIFont boldSystemFontOfSize:12]];
        }
    }           
}
like image 30
stack2012 Avatar answered Oct 18 '22 18:10

stack2012