2

I wanted to color each segment in my UISegmentedControl in a different color. I used the following Swift code (there were some changes with segmentedControl in iOS 13):

segmentedControl.selectedSegmentTintColor = .white
let col: UIColor = .yellow
var subViewOfSegment: UIView = segmentedControl.subviews[2] as UIView
subViewOfSegment.layer.backgroundColor = col.cgColor

This works in general, one segment is now coloured. However, the selected segment is not shown anymore. The selected segment is supposed to be white, but it seems to be overlaid by the colour. The following image show how it looks when I select each segment from left to right:

enter image description here

I already tried subViewOfSegment.backgroundColor = col instead (same effect) or subViewOfSegment.tintColor = col (no effect at all in iOS 13) but I can't get the colors without hiding the selection. On other posts I only find this answer which doesn't say how to color unselected segments.

Nina
  • 53
  • 5
  • 1
    It's bad practice to bypass the available APIs and [pook](https://en.wikipedia.org/wiki/PEEK_and_POKE) inside UI elements. You'd have to check if this works on all iOS versions you want to support and this might break in a newer version. – meaning-matters Aug 12 '22 at 21:08
  • What do you mean by "available APIs"? Can I change the colours of individual segments in Xcode via the object inspector? I only found the option to change the color of the whole segment there. Thanks anyways for the reply! – Nina Aug 12 '22 at 22:05
  • Kind remark: please start comments with @. With "available APIs" I mean what Apple has documented you can do. – meaning-matters Aug 13 '22 at 08:59
  • I believe u should use collectionView or UIButtons in stackView. – Muhammad Hasan Irshad Aug 25 '22 at 19:24

4 Answers4

2

iOS 13 (Xcode 13.4) Segment Control 100% Working

Segmentcontroller selected backgroundColor

mySegmentedControl.selectedSegmentTintColor = .white
let subView = mySegmentedControl.subviews[1] as UIView
subView.layer.backgroundColor = UIColor.yellow.cgColor
Nabeel ali
  • 196
  • 1
  • 5
  • Sorry this really doesn't work for me.. I even updated Xcode to align everything with your solution, but the color still hides the selection. Thanks for testing it though! – Nina Aug 27 '22 at 20:29
1
let subViewOfSegment: UIView = segmentedControl.subviews[1] as UIView
subViewOfSegment.backgroundColor = UIColor.red
subViewOfSegment.layer.zPosition = -999

> above solution is not proper but one of the way you can achieve it. you need manage one more label while select segment is red"`
`
Arjun
  • 126
  • 4
  • Great, changing the z position was the only thing that worked for me! It's a workaround but the best I could find – Nina Aug 27 '22 at 20:30
1

You can do it by using the following code:

init(){
    UISegmentedControl.appearance().backgroundColor = .yellow
}

var body: some View{
     your code…
}

if you want to change the selected segment’s color, you can use:

UISegmentedControl.appearance().selectedSegmentTintColor = .blue

to change it. I hope these codes can help you :D

For detail, you can visit here.

Yale Y
  • 58
  • 9
  • this seemed promising but I didn't get it to work for individual segments (your code is only for updating the backgroundcolor of the whole segmentedContol) – Nina Aug 27 '22 at 23:26
  • Oh, i see, then you can use the subviews of segment like the answer that you ticked. – Yale Y Aug 28 '22 at 04:47
0

Using Apple APIs, you could try drawing an image with the 4 colors and set that as background using setBackgroundImage(_:for:barMetrics:).

Here's some code to draw a 40x10 image with just one color to get you started:

    let rect = CGRect(origin: CGPoint(x: 0, y:0), size: CGSize(width: 40, height: 10))
    UIGraphicsBeginImageContext(rect.size)
    let context = UIGraphicsGetCurrentContext()!

    context.setFillColor(color.cgColor)
    context.fill(rect)

    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

To get an image with your four colors, you need to repeat context.setFillColor(<varying color>) and context.fill(<varying rect>) four times.

The image should stretch, which means you it only needs to have four equally sized colored rectangles; you don't need to create it in the exact size of the segmented control.

You can then set the selected segment color using the selectedSegmentTintColor property.

meaning-matters
  • 21,929
  • 10
  • 82
  • 142
  • thanks for your help; however, this does not solve my problem. When I use setBackgroundImage on the whole segmentedControl, the selected segment also does not show up anymore. I edited my post above to make the error more clear. Maybe there is something like sendToBack that could solve the problem? – Nina Aug 18 '22 at 21:35