9

In iOS 6/7, I have used UISegmentedControl with background images to create an effect like so:

Customized UISegmentedControl

I accomplished this by setting the background image for the UISegmentedControl for each of standard states, like so:

UIImage *segmentedControlBackgroundImage = [UIImage imageNamed:@"profileSegmentedControlBackground"];
UIImage *segmentedControlBackgroundSelectedImage = [UIImage imageNamed:@"profileSegmentedControlBackgroundSelected"];

[self.segmentedControl setBackgroundImage:segmentedControlBackgroundImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:segmentedControlBackgroundImage forState:UIControlStateDisabled barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:segmentedControlBackgroundSelectedImage forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:segmentedControlBackgroundSelectedImage forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];

When a segment becomes select or is highlighted, it has the nice blue bar underneath and I set text attributes to change the text color to be blue. There's some extra code for the dividers, but I think that's unrelated so I've omitted it.

My problem is that in iOS 8, there are a couple of actions that cause the background of the segment to turn gray and look bad; One being when you change your selection, the cell you tapped turns gray until the transition completes, and the other is that if you tap and hold an already selected segment, it turns gray. Both look identical and can be seen below.

UISegmentedControl with strange highlighting

Some extra pieces of possibly relevant information:

  • The tintColor for the segmentedControl is clear
  • I'm not subclassing UISegmentedControl
  • I haven't changed any properties for UISegmentedControl using its appearance proxy
  • I am using 1 point wide images for the background images and UISegmentedControl is automatically determining the capInsets and tiling the image
Acey
  • 8,048
  • 4
  • 30
  • 46
  • I am also finding this. Did you ever find a solution to your problem? – GraemeArthur Apr 11 '15 at 17:31
  • Nope. The best I could do was to make sure very little happened on the main thread after changing tabs so it appeared miscolored for as little time as possible. – Acey Apr 11 '15 at 17:44

2 Answers2

13

The reason the segment turns grey on selecting an already selected segment is because the segmented control is missing the state for selected and highlighted at the same time.

In your case calling:

[self.segmentedControl setBackgroundImage:segmentedControlBackgroundSelectedImage forState:UIControlStateSelected | UIControlStateHighlighted barMetrics:UIBarMetricsDefault];

should fix that problem.

when you change your selection, the cell you tapped turns gray until the transition completes

I couldn't reproduce that one, but perhaps this will fix both issues.

GraemeArthur
  • 507
  • 5
  • 13
  • Great that did it! And yep it did fix both problems. Thanks for the help. What an odd API. I'm customizing the divider images too so this will just about double the lines needed for that customization. – Acey Apr 12 '15 at 21:37
  • Never occurred to me that states could be masked together. Thanks for nothing Apple doc! – Brenden Jan 09 '16 at 02:19
7

Just in case, in Swift that would be (UPD for Swift 4)

segmentedControl.setBackgroundImage(image, forState: .selected, barMetrics:.Default)

segmentedControl.setBackgroundImage(image, forState: .highlighted, barMetrics:.Default)

nikans
  • 2,468
  • 1
  • 28
  • 35
  • 1
    THANK YOU! How do people figure out stuff like this? Docs are no help. – Brenden Jan 09 '16 at 02:27
  • @DaniSpringer cuz it's Swift 2? try to start enum options with lowercase – nikans Aug 03 '18 at 18:13
  • @DaniSpringer true, I haven't looked into that, but it seems that passing an array doesn't work anymore. try 2 separate statements for `selected` and `highlighted`. – nikans Aug 06 '18 at 14:30
  • I did that. Actually I made a for loop, creating an array for the items, and accessing them in the loop. Thanks –  Aug 06 '18 at 18:03
  • 1
    What worked for me was setting (selected, highlighted, normal) on single lines. Then setting selected and highlighted together like this. ``self.setBackgroundImage(backgroundImage, for: .normal, barMetrics: .default) self.setBackgroundImage(backgroundImage, for: .selected, barMetrics: .default) self.setBackgroundImage(backgroundImage, for: .highlighted, barMetrics: .default) self.setBackgroundImage(backgroundImage, for: [.selected, .highlighted], barMetrics: .default)`` – mikemike396 Sep 16 '19 at 17:40