【问题标题】:How can I calculate correct widths for UISegmentedControl segments?如何计算 UISegmentedControl 段的正确宽度?
【发布时间】:2011-10-05 00:48:01
【问题描述】:

我正在尝试使用 UISegmentedControl,但无法计算段的宽度。该控件使段的宽度都相同,这对于某些标题不起作用,例如:

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

如果我知道哪种字体并调用 setWidth:forSegmentAtIndex: 方法,我可以编写代码来计算段宽度,但我怎样才能获得字体?还是有其他方法?

左边和中间部分的标题不固定,所以我不能硬编码宽度。

【问题讨论】:

  • 你必须使用 UILabel 自定义它
  • 没错。出于同样的原因,我无法使用它。
  • 我已经添加了自定义代码。使用它,然后将其作为子视图添加到您想要的任何视图。方法 pickone 选择器对每个按下的段执行相应的操作。可以通过在该方法中获取段标题索引值来实现。希望这会有所帮助。
  • 我现在已经删除了一些不必要的代码

标签: iphone ios uisegmentedcontrol uifont


【解决方案1】:
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]];
        }
    }           
}

【讨论】:

  • 不客气! :) 编码快乐!
  • 我真的不想深入到子视图中,但似乎没有其他方法。我确实通过从标签子视图中获取字体来让它工作,然后我可以计算标题宽度并平均划分空间。
  • 是的。当我遇到同样的麻烦时,这是我能找到的最佳解决方案。
【解决方案2】:

编辑:更简单的选择可能是使用@Camsoft 的answer here 中提到的iOS 5 属性apportionsSegmentWidthsByContent


好吧,我最终通过子视图获得了 UIFont(这可能会在未来的 iOS 中中断)。作为一个模块化/重用爱好者,我编写了这个例程来完成它,然后分配空间,以便控件中的段均匀分布于标题。

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

【讨论】:

  • 这是一些可靠的代码!我刚刚将此方法添加到我的视图控制器中,并在我的 viewDidLoad 方法中将我的分段控件传递给它,它只负责其余的工作!甚至不需要修改任何东西。
  • 除非它不处理没有剩余空间的情况,即您的标签文本对于控件的总宽度来说太宽,但除了小缺陷之外它可以工作;-)
  • 谢谢你!不幸的是,这不再适用于 iOS 7。更正和简化的功能已发布here
【解决方案3】:

如果您可以支持 iOS 5 及更高版本,则可以使用属性 apportionsSegmentWidthsByContent 并将其设置为 YES

来自 iOS 5 docs:

apportionsSegmentWidthsByContent

表示控件是否 尝试根据内容宽度调整段宽度。

@property(nonatomic) BOOL apportionsSegmentWidthsByContent

讨论

如果该属性的值为YES,对于宽度值为 为 0,控件尝试根据其调整段宽度 内容宽度。

【讨论】:

  • 甜蜜。适用于 ios 9.3、Swift。
【解决方案4】:

iOS 7.1.1 友好。我们只计算了 UISegmentedControl 新的帧大小,其余的(段比例)将由 iOS 解决(基于 apportionsSegmentWidthsByContent)。

请注意,如果启用自动布局,这将不起作用。

void styleSegment_fitTitles(UISegmentedControl *segCtrl) {

    // Fit segments' titles
    [segCtrl sizeToFit];

    CGFloat em = font.pointSize;
    CGRect segCtrlRect = segCtrl.bounds;
    CGFloat segCtrlWidth = segCtrlRect.size.width + segCtrl.numberOfSegments*em;
    CGFloat segCtrlHeight = segCtrlRect.size.height + em;
    CGFloat segmentY = segCtrl.frame.origin.y - (segCtrlHeight - segCtrlRect.size.height)/2;
    segCtrl.frame = CGRectMake(segCtrl.frame.origin.x, segmentY, segCtrlWidth, segCtrlHeight);
}

【讨论】:

  • CGFloat segCtrlWidth = segCtrlRect.size.width + segCtrl.numberOfSegments*em;这不是计算宽度的有效方法,您只是将段数乘以字体大小。有效的方法应该是根据每个段中的文本计算宽度
  • @HabibAli - 你是对的 - 这就是为什么有一个 em 单位,如果你明白我的意思的话。因此,如果您对此感到满意,请重新考虑您的反对意见。
  • em = font.pointSize 并不令人满意,因为字体大小仅定义高度而不是每个段的文本宽度。明白了吗?
  • 请注意,您所有的“魔法”都发生在[segCtrl sizeToFit](基于apportionsSegmentWidthsByContent)中,em 在这里仅用作填充(空白)。
猜你喜欢
  • 2015-02-20
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 2014-06-02
  • 1970-01-01
  • 2013-05-26
  • 1970-01-01
  • 2012-05-21
相关资源
最近更新 更多