UISegmentedControl不尊重为UIControlStateDisabled设置的分隔符图像

时间:2012-03-12 00:25:22

标签: ios ios5 uisegmentedcontrol uiappearance

我正在使用iOS 5中的新UIAppearance API来设置带有自定义图形的UISegmentedControl样式。我需要能够在执行期间设置一些段被禁用,但UIAppearance方法似乎不允许我为UIControlStateDisabled状态设置分频器图像。

我在打电话:

[[UISegmentedControl appearance] setDividerImage:disabledSelectedImage
                                    forLeftSegmentState:UIControlStateDisabled
                                    rightSegmentState:UIControlStateSelected
                                    barMetrics:UIBarMetricsDefault];

其中disabledSelectedImage是来自此资源的可调整大小的图片:

disabled-selected-image

然而,当我将左段设置为禁用([UISegmentedControl setEnabled:forSegmentAtIndex:])时,结果如下:

UISegmentedControl UI glitch

您可以清楚地看到UISegmentedControl默认使用UIControlStateNormal - UIControlStateNormal分频器图片。

我很高兴使用UIControlStateDisabled

设置背景图片
[[UISegmentedControl appearance] setBackgroundImage:disabledImage
                                    forState:UIControlStateDisabled
                                    barMetrics:UIBarMetricsDefault];

(并且在处于禁用状态时尊重我提供的图像)但不是分割器图像。有没有人遇到这个或找到了解决方案?

6 个答案:

答案 0 :(得分:3)

我已经确定这必须是iOS错误并且已经向Apple提交了radar。我现在解决问题的方法是删除段,而不是禁用它们。

答案 1 :(得分:1)

有点丑陋的解决方法,但我设法用以下方法修复它,直到苹果自己修复它。

首先,您需要继承UISegmentedControl并添加以下内容:

@implementation MJSegmentedControl

- (void)layoutSubviews
{
    [super layoutSubviews];
    NSInteger cachedIndex = self.selectedSegmentIndex;
    self.selectedSegmentIndex = 0;
    self.selectedSegmentIndex = cachedIndex;
}

@end

答案 2 :(得分:0)

我还没有必要使用iOS 5的外观控件,但如果其他所有方法都失败了,你可以添加可调整大小的图片作为分段控件的子项以掩盖丑陋。这是一个黑客,但它可能会工作,并将相对向前兼容。只需确保适当设置自动调整遮罩。

答案 3 :(得分:0)

我有同样的问题,它似乎真的是一个错误。但是,我找到了解决方案(解决方法)。

我已将XIB文件与控制器一起使用。在XIB文件中,刚刚放置了分段控件,所有自定义都在-viewDidLoad方法中完成。

然后我创建了一个UIView子类,它代表了XIB中的整个视图。它使所有视图自定义代码都可以移动到此UIView子类的-awakeFromNib方法。移动此代码后,分割器图像设置正确。

答案 4 :(得分:0)

正如费尔南多在这篇帖子中所建议的那样: Customizing UISegmentedControl in iOS 5

您可以尝试通过以下方式在主队列上调度UISegmentedControl设置:

dispatch_async(dispatch_get_main_queue(),^{
    // disable part of the segmented control
    [self.eventScopeSegmentedControl setEnabled:NO forSegmentAtIndex:2];
});

我在viewDidLoad中做了这个并且它工作了一段时间但是当我的应用程序在启动时真的很忙时,这并不总是有效。我猜测有一种竞争条件可能仍会恢复你在外观代理工作时所做的任何设置。

我添加了另一个丑陋的黑客来在viewWillAppear(在调用super:viewWillAppear之后)中使用一个标志(从viewWillLoad设置)进行此调用,以确保它只运行一次。

答案 5 :(得分:0)

实际上有一种非常简单的方法可以完成这项工作。当前的行为显然是一个错误,所以这不是一个理想的解决方案,而只是一个非常有效的解决方法。即,使用额外的UIView作为“禁用的视觉提示”。

一般步骤:

  1. 将UIView作为兄弟添加到UISegmentedControl。确保UIView位于UISegmentedControl
  2. 前面
  3. 将所需的颜色和透明度应用于UIView以匹配您的应用程序皮肤
  4. 将UIView移到UISegmentedControl
  5. 的顶部
  6. 将UIView塑造成具有UISegmentedControl
  7. 的顶部的确切大小
  8. 在UIView上应用圆角以反映UISegmentedControl的确切形状
  9. 当UISegmentedControl应该被禁用时,只需显示UIView并禁用UISegmentedControl上的用户交互。

    当启用UISegmentedControl时,只需隐藏UIView并在UISegmentedControl上启用用户交互。

    在这两种情况下都不要更改UISegmentedControl.enabled属性。

    请注意,它似乎有很多步骤,但所有这些都可以编码,以便添加对禁用自定义UISegmentedControl的支持在将其添加到配置分段控制方法后变得非常简单。

    以下是我的自定义分段控件在应用此解决方案时的外观:

    启用分段控制

    enabled segmented control

    “已停用”分段控制

    disabled segmented control

    以下是一些感兴趣的代码段:

    塑造UIView以匹配UISegementedControl(加载时间配置)

      UISegmentedControl* segmentedControl = ...
      //Segmented Control disabled visual cue view
      UIView* view = ...
    
      //Step #2       
      view.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.6];
    
      //Step #3 and #4
      view.frame = segmentedControl.frame;
    
      //Step #5
      view.layer.cornerRadius = 5
      view.clipsToBounds = YES;
    
      //Ensure this is disabled by default
      view.userInteractionEnabled = NO;
    

    启用/“禁用”UISegementedControl(运行时状态更改)

    BOOL segmentedControlEnabled = ...
    
    if(segmentedControlEnabled) {
      segmentedControl.userInteractionEnabled = YES;
      view.hidden = YES;    
    } else {     
      segmentedControl.userInteractionEnabled = NO;
      view.hidden = NO;
    }
    

    就是这样。

    -