这个问题相当简单,但我在许多UISegmentedControl帖子中看不到任何真正满足我需求的内容:
环境: 我有一组显示在UISegmentedControl中的目录。它是一个平面层次结构,只有很少的目录,因此这是显示它们的最佳方式。
选择一个段将使用该目录的内容填充下面的UITableView。
我可以通过编程方式选择一个给定的片段,这样我就可以根据需要选择合适的片段。
效果很好。
问题:
其中一个目录是“默认”目录,它将包含已存在的项目和新项目的混合。
我想要对该段进行标记,以便有一个指示其中有多少个新段,以便人们知道如果尚未为它们选择它们。
这意味着我需要访问UISegmentedControl中的实际子视图和诸如此类的东西。
不那么容易。制作徽章是孩子的游戏。找出放置徽章的位置是成年人的东西。
看起来Apple故意隐藏对细分的直接访问。您只能影响整个控件。
有没有人对如何修改一个细分,或者甚至找出该细分的位置有任何建议?
widthForSegmentAtIndex:。函数似乎毫无价值,因为它是否会给你任何有用的信息是任意的。
答案 0 :(得分:3)
不,widthForSegmentAtIndex:
返回的值不是任意的。正如您在文档中看到的那样,它返回段的宽度或0.0,这意味着段是自动调整的。
有一种方法可以获得每个细分的框架。
或代码:
就我在iOS7上看到的而言,片段之间的“边界”不是片段宽度的一部分。
CGFloat autosizedWidth = CGRectGetWidth(self.segment.bounds);
// iOS7 only?!
autosizedWidth -= (self.segment.numberOfSegments - 1); // ignore the 1pt. borders between segments
NSInteger numberOfAutosizedSegmentes = 0;
NSMutableArray *segmentWidths = [NSMutableArray arrayWithCapacity:self.segment.numberOfSegments];
for (NSInteger i = 0; i < self.segment.numberOfSegments; i++) {
CGFloat width = [self.segment widthForSegmentAtIndex:i];
if (width == 0.0f) {
// auto sized
numberOfAutosizedSegmentes++;
[segmentWidths addObject:[NSNull null]];
}
else {
// manually sized
autosizedWidth -= width;
[segmentWidths addObject:@(width)];
}
}
CGFloat autoWidth = floorf(autosizedWidth/(float)numberOfAutosizedSegmentes);
for (NSInteger i = 0; i < [segmentWidths count]; i++) {
id width = segmentWidths[i];
if (width == [NSNull null]) {
[segmentWidths replaceObjectAtIndex:i withObject:@(autoWidth)];
}
}
CGFloat x = CGRectGetMinX(self.segment.frame);
for (NSInteger i = 0; i < [segmentWidths count]; i++) {
NSNumber *width = segmentWidths[i];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(x, CGRectGetMaxY(self.segment.frame) + 1, [width floatValue], 30)];
view.backgroundColor = [UIColor colorWithHue:i/(float)[segmentWidths count] saturation:1 brightness:1 alpha:1];
[self.view addSubview:view];
x = CGRectGetMaxX(view.frame)+1;
}
这产生以下结果:
我建议您不要将徽章添加为UISegmentedControl的子视图,您可以将其添加到segmentedControl的superView中。你的徽章基本上应该是segmentedControl的兄弟姐妹
请向Apple提交enhancement request。他们不会让我们访问各个子视图,但他们至少可以告诉我们这些细分的实际大小。
答案 1 :(得分:2)
你知道segmentedControl的大小,你知道段的数量。只需除以得到每个段的宽度。它们的宽度都相同。
然后将徽章放在segmentedControl顶部的适当x位置。
答案 2 :(得分:1)
更新:我做了一些调整,我 STILL 没有完美,但这似乎给出了一个很好的近似,给出或取一个像素。
只要控件很小,那么上面的效果很好,但是有一些错误。可能是因为我没有在某个地方拍摄几个像素的像素。
以下是我在my test app中所做的事情(注意:项目已更新为有更多测试控件)。
首先,我在UISegmentedControl类上声明了一个类扩展:
@interface UISegmentedControl (Overload)
- (NSArray*)mapUISegmentedControl;
@end
然后,我实现它,就像这样:
@implementation UISegmentedControl (Overload)
- (NSArray*)mapUISegmentedControl
{
NSMutableArray *segmentFrames = [NSMutableArray arrayWithCapacity:[self numberOfSegments]];
NSInteger numberOfAutosizedSegments = 0;
double ios7Coefficient = [[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0 ? 1 : 0;
double autosizedWidth = CGRectGetWidth ( [self bounds] ) - 1;
for ( NSInteger i = 0; i < [self numberOfSegments]; i++ )
{
double width = [self widthForSegmentAtIndex:i];
if ( width == 0.0f )
{
autosizedWidth -= 1;
// If this is an auto-sized, we blank out the holding space for it.
numberOfAutosizedSegments++; // Add this to our count of auto-sized segments.
[segmentFrames addObject:[NSNull null]];
}
else
{
// If the size has been explicitly set, we use that, and create a simple rect.
autosizedWidth -= (width + ios7Coefficient);
CGRect frame = CGRectMake ( 0, 0, width, CGRectGetHeight ( [self bounds] ) );
[segmentFrames addObject:[NSValue valueWithCGRect:frame]];
}
}
// We divvy up the leftover space for the autoscales.
double autoWidth = (autosizedWidth + ios7Coefficient) / (double)numberOfAutosizedSegments;
double x = 0;
for ( NSInteger i = 0; i < [segmentFrames count]; i++ )
{
CGRect frame = CGRectZero;
double width = 0;
// If this is auto-sized (flagged by a null object), then make an autosized rect.
if ( segmentFrames[i] == [NSNull null] )
{
width = ceil ( autoWidth - ios7Coefficient );
}
else // Otherwise, use the rect they supplied.
{
width = CGRectGetWidth ( [(NSValue*)[segmentFrames objectAtIndex:i] CGRectValue] );
}
width += 1;
frame = CGRectMake ( x, 0, width, CGRectGetHeight( [self bounds] ) );
[segmentFrames replaceObjectAtIndex:i
withObject:[NSValue valueWithCGRect:frame]
];
// The x origin keeps up with the control.
x += width;
}
return [NSArray arrayWithArray:segmentFrames];
}
@end
接下来,我在布局响应中调用它,如下所示:
@implementation DemoViewController
- (void)drawOverlays
{
NSArray *segmentMap = [[self segmentedControl] mapUISegmentedControl];
if ( ![self colorBand] )
{
_colorBand = [[NSMutableArray alloc] init];
}
else
{
for ( UIView *view in [self colorBand] )
{
[view removeFromSuperview];
}
[[self colorBand] removeAllObjects];
}
for ( NSInteger i = 0; i < [segmentMap count]; i++ )
{
CGRect frame = [(NSValue*)[segmentMap objectAtIndex:i] CGRectValue];
frame.size.height /= 2.0;
frame.origin.y = [[self segmentedControl] frame].origin.y + [[self segmentedControl] frame].size.height;
UIView *view = [[UIView alloc] initWithFrame:frame];
view.backgroundColor = [UIColor colorWithHue:i/(float)[segmentMap count] saturation:1 brightness:1 alpha:0.5];
[[self view] addSubview:view];
[[self colorBand] addObject:view];
}
}
- (void)viewDidLayoutSubviews
{
[self drawOverlays];
}
@end
这适用于iOS 6和7,但似乎偶尔会出现半像素错误。
结果显示如下: