How to set the hue color of a UISegmentedControl for an individual segment

Starting to learn Swift and trying to convert this ObjectiveC code:

[[mySegmentedControl.subviews objectAtIndex:0] setTintColor:[UIColor blueColor]] 

This correctly sets the hue color of the first segment.


This is closest to getting the Swift version of the same code:

 mySegmentedControl?.subviews[0].tintColor = UIColor.blueColor() 

I get the error '@Ivalue $T9' is not identical to 'UIColor!!'


I do not understand what this error means. When I look at the .tintColor method, it lists UIColor!? , and I haven't found what it means !? together in Swift.

+6
source share
8 answers

This will solve your problem:

 var subViewOfSegment: UIView = mySegmentedControl.subviews[0] as UIView subViewOfSegment.tintColor = UIColor.blueColor() 

you also can

 (mySegmentedControl.subviews[0] as UIView).tintColor = UIColor .blueColor() 
+18
source

The easiest way I've found is this:

 segmentControl.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.redColor()], forState: UIControlState.Selected) 
+9
source

This code works great with the latest version of Swift from August 2019 (Swift 3.0)

Here, this code that I implemented is an extension for the Segment control and can be used for all segment controls in the application, where the code set must be defined in the application class.

The extension method can be used directly in the application, you can also add all the settings for the same method or different methods in the extension class, as shown below.

 extension UISegmentedControl { func setSegmentStyle() { setBackgroundImage(imageWithColor(color: backgroundColor!), for: .normal, barMetrics: .default) setBackgroundImage(imageWithColor(color: tintColor!), for: .selected, barMetrics: .default) setDividerImage(imageWithColor(color: UIColor.clear), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default) let segAttributes: NSDictionary = [ NSForegroundColorAttributeName: UIColor.gray, NSFontAttributeName: UIFont(name: "System-System", size: 14)! ] setTitleTextAttributes(segAttributes as [NSObject : AnyObject], for: UIControlState.selected) } // create a 1x1 image with this color private func imageWithColor(color: UIColor) -> UIImage { let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0) UIGraphicsBeginImageContext(rect.size) let context = UIGraphicsGetCurrentContext() context!.setFillColor(color.cgColor); context!.fill(rect); let image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image! } } 

You can use the code below for segments everywhere

  self.mySegment.setSegmentStyle() 

enter image description here

+3
source

To change the hue color of a selected segment

Use the modified value event for UISegmentControl to sort the segments in order by their x value, then loop through and compare the selectedSegmentIndex property. Here is an example assuming segmented control of 4 segments:

 @IBAction func indexChanged(sender: UISegmentedControl) { let sortedViews = sender.subviews.sort( { $0.frame.origin.x < $1.frame.origin.x } ) for (index, view) in sortedViews.enumerate() { if index == sender.selectedSegmentIndex { view.tintColor = UIColor.blueColor() } else { view.tintColor = UIColor.lightGrayColor() } } } 

Then in viewDidLoad set tintColor for the initially selected segment, in which case it will be the first:

 let sortedViews = segmentedControlOutletVariable.subviews.sort( { $0.frame.origin.x < $1.frame.origin.x } ) sortedViews[0].tintColor = UIColor.blueColor() 
+2
source

After analyzing and testing the many answers to this and other similar questions, I realized that with a third-party custom segmented control it will be much easier and safer to make settings than trying to hack Apple UISegmentedControl.

Here is an example setup with XMSegmentedControl (Swift 3).

Some of the code:

  mySegmentControl.delegate = self mySegmentControl.font = UIFont.systemFont(ofSize: 12) 

And some in Interface Builder (you can do it in code, if you want):

enter image description here

Result:

enter image description here

In my case, it is very similar to the system one, but there are still minor differences that I had to do exactly as the developer would like.

Note that XMSegmentedControl does not allow you to have different background colors for different segments, but you can easily add this if necessary, as it is a simple .swift file that is very easy to understand and change.

+1
source

sender.subviews.sort does not work in Swift 4, and a link to delete a border is provided in How to remove a border from a segmented control

 extension UISegmentedControl { // create a 1x1 image with this color private func imageWithColor(color: UIColor) -> UIImage { let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0) UIGraphicsBeginImageContext(rect.size) let context = UIGraphicsGetCurrentContext() context!.setFillColor(color.cgColor); context!.fill(rect); let image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image! } func removeBackgroundColors() { self.setBackgroundImage(imageWithColor(color: .clear), for: .normal, barMetrics: .default) self.setBackgroundImage(imageWithColor(color: .clear), for: .selected, barMetrics: .default) self.setDividerImage(imageWithColor(color: UIColor.clear), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default) } struct viewPosition { let originX: CGFloat let originIndex: Int } func updateTintColor(selected: UIColor, normal: UIColor) { let views = self.subviews var positions = [viewPosition]() for (i, view) in views.enumerated() { let position = viewPosition(originX: view.frame.origin.x, originIndex: i) positions.append(position) } positions.sort(by: { $0.originX < $1.originX }) for (i, position) in positions.enumerated() { let view = self.subviews[position.originIndex] if i == self.selectedSegmentIndex { view.tintColor = selected } else { view.tintColor = normal } } } } override func viewDidLoad() { super.viewDidLoad() mySegment.removeBackgroundColors() mySegment.backgroundColor = .clear mySegment.updateTintColor(selected: myNavigationColor, normal: text1Color) } 
0
source

The solution is designed for only two segments, but it can easily be expanded as much as you need. First I suggest creating an enumeration:

  enum SegmentedSections: Int { case first, case second } 

Then create a function and call this function in viewDidLoad, and also call it every time .valueChanged happens in segmentedControl:

 func setProperSegmentedControlColoring(_ segment: UISegmentedControl, type: SegmentedSections) { setSeparatorImages(for: segment, with: type) let subviews = segment.subviews let sortedViews = subviews.sorted(by: { $0.frame.origin.x < $1.frame.origin.x }) for (index, view) in sortedViews.enumerated() { switch type { case .first: if index == segment.selectedSegmentIndex { view.tintColor = .red } else { view.tintColor = .blue } case .second: if index == segment.selectedSegmentIndex { view.tintColor = .blue } else { view.tintColor = .red } } } } 

You will also need to change the divider image accordingly:

 func setSeparatorImages(for segment: UISegmentedControl, with type: EarnType) { switch type { case .first: let image = UIImage(color: .red) segment.setDividerImage(image, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default) case .second: let image = UIImage(color: .blue) segment.setDividerImage(image, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default) } } 

You will also need an extension for UIImage. You can find it here.

0
source
 class MyUISegmentedControl: UISegmentedControl { required init(coder aDecoder: NSCoder){ super.init(coder: aDecoder)! for subViewOfSegment: UIView in subviews { subViewOfSegment.tintColor = UIColor.red } } } 
-1
source

Source: https://habr.com/ru/post/984344/


All Articles