iOS7中UISegmentedControl setImage存在Bug

25

我的应用程序中有一个UISegmentedControl。自iOS7 GM版本以来,在iOS7设备上运行时,我使用的图像未显示。还有其他人遇到这个问题吗?

以下是它在iOS6.1及更早版本中的样子iOS6-ScreenShot .

这是它在iOS7中的样子iOS7-ScreenShot .

代码如下:

self.theSegmentedControl.frame = CGRectMake(self.theSegmentedControl.frame.origin.x, self.theSegmentedControl.frame.origin.y, 320, 35);
[self.theSegmentedControl setBackgroundImage:[UIImage imageNamed:@"img_toggleInactive"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.theSegmentedControl setImage:[UIImage imageNamed:@"btn_onceActive"] forSegmentAtIndex:0];
[self.theSegmentedControl setImage:[UIImage imageNamed:@"btn_recurringInactive"] forSegmentAtIndex:1];
[self.theSegmentedControl setImage:[UIImage imageNamed:@"btn_scheduledInactive"] forSegmentAtIndex:2];
[self.theSegmentedControl setDividerImage:[UIImage imageNamed:@"separator"] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

有人找到解决办法了吗?


这不是错误,而是一个特性!苹果公司做出了非常奇怪的选择,将分段控件中的图像全部着色。在我的应用程序中,我使用了一个分段控件来选择颜色,现在我的颜色都是蓝色的! - Martin
4个回答

61

哇喔!下面是解决方法:

//Add clear color to mask any bits of a selection state that the object might show around the images
self.theSegmentedControl.tintColor = [UIColor clearColor];

UIImage *onceActive;
UIImage *recurringActive;
UIImage *scheduledActive;
UIImage *separator;

//Setting imageWithRenderingMode: to imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal for iOS7 is key
if ([UIImage instancesRespondToSelector:@selector(imageWithRenderingMode:)]) {
    onceActive = [[UIImage imageNamed:@"btn_onceActive"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    recurringActive = [[UIImage imageNamed:@"btn_recurringInactive"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    scheduledActive = [[UIImage imageNamed:@"btn_scheduledInactive"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    separator = [[UIImage imageNamed:@"separator"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];

}
else {
    onceActive = [UIImage imageNamed:@"btn_onceActive"];
    recurringActive = [UIImage imageNamed:@"btn_recurringInactive"];
    scheduledActive = [UIImage imageNamed:@"btn_scheduledInactive"];
    separator = [UIImage imageNamed:@"separator"];
}


[self.theSegmentedControl setImage:onceActive forSegmentAtIndex:0];
[self.theSegmentedControl setImage:recurringActive forSegmentAtIndex:1];
[self.theSegmentedControl setImage:scheduledActive forSegmentAtIndex:2];
[self.theSegmentedControl setDividerImage:separator forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

2
这不是“变通方法”,在 WWDC 视频中明确指出在那种情况下需要这样做。 - Anya Shenanigans
25
没有新方法的代码可以在iOS6.1及以下版本中工作,但在7中停止了。文档或控制台没有任何指示要做任何不同的事情。责任不在我身上,去观看所有的WWDC视频。我会继续将此视为一个错误,谢谢。 - kevmalek
2
你是否使用新的SDK重新编译了代码?文档明确指出:分段图标您可以使用图像代替标题文本来表示您的分段。请注意,除非您将其呈现模式显式设置为UIImageRenderingModeAlwaysOriginal,否则分段控件中的分段图像将自动呈现为模板图像。有关更多信息,请参见模板图像(我不会链接到它,因为该链接仍处于预发布状态)。 - Anya Shenanigans
1
你说得对,在过渡指南中提到了该行为,谢谢。 - kevmalek
@newlife 是的,请使用这个。这不是一种变通方法,而是UISegmentedControl在iOS7中前进的新行为。 - kevmalek
显示剩余3条评论

18

Xcode 6/iOS 8更新内容

现在你可以在界面生成器中完成此操作。

只需将图像文件添加到资源目录中,并将其“呈现为”原始图像而非默认图像即可。

Xcode 5

新的UISegmented控件使用色调颜色来使用模板模式调整图像的颜色。你需要将这些图像呈现为原始图像而不是模板。

如评论中建议的那样执行以下操作:

UIImage* onceActive = [UIImage imageNamed:@"btn_onceActive"];
if (IOS_7_MACRO)
    onceActive = [onceActive imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
[self.theSegmentedControl setImage:onceActive forSegmentAtIndex:0];

你如何告诉用户从XIB/Interface Builder使用AlwaysOriginal渲染模式? - Speckpgh
2
至少在UISegmentedControl中,我没有在IB中看到那个选项 :( - João Nunes
1
从Xcode 6开始,您可以在资产目录属性中为每个资产设置渲染模式 :D - João Nunes
似乎iOS 7忽略了这个设置。我正在使用Xcode 6.1,在iOS 8上运行时该设置有效,但在iOS 7上无效。 - mahboudz
@mahboudz 谢谢,我已经更新了答案。我没有在iOS 7上测试过,现在太懒得去做了:D - João Nunes
我发现即使正确设置了资产属性也不足够;我需要用类似这样的东西来激活它: - pickwick

7

使用此代码在iOS 7上使用xCode 5.0设置分段控件中的图像

if ([UIImage instancesRespondToSelector:@selector(imageWithRenderingMode:)]) {

    [segmentControl setImage:[[UIImage imageNamed:@"image.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forSegmentAtIndex:0];

}
else {
    [segmentControl setImage:[UIImage imageNamed:@"image.png"] forSegmentAtIndex:0];
}

2

创建一个分类可能会很有用:

@interface UISegmentedControl (UISegmentedControlAdditions)
    -(void)setImageRenderingMode:(UIImageRenderingMode)renderingMode;
@end    

@implementation UISegmentedControl (UISegmentedControlAdditions)
    -(void)setImageRenderingMode:(UIImageRenderingMode)renderingMode {
        for (int index=0; index < [self numberOfSegments]; index++) {
            UIImage * image = [self imageForSegmentAtIndex:index];
            [self setImage:[image imageWithRenderingMode:renderingMode] forSegmentAtIndex:index];
        }
    }

... 然后只需调用

if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
    [colorSegmentedControl setImageRenderingMode:UIImageRenderingModeAlwaysOriginal];

imageWithRenderingMode: 已经存在于 UIImage 中。那么为什么要创建类别?此方法只在 iOS 7.0 及以上版本中可用。 - Akshit Zaveri
是的,imageWithRenderingMode:也是一个UIImage方法:这个例子正在使用它。为什么要创建一个类别?因为它比手动配置控件更简洁和有用。当然,通过创建自己的UISegmentedControl类甚至更好。 - Martin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接