How to set UISegmentedControl Tint Color for individual segment

天涯浪子 提交于 2020-01-01 05:04:32

问题


Starting to learn Swift and am attempting to convert this ObjectiveC code:

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

This correctly sets the tint color of the first segment.


This is the closest I've come to getting a Swift version of the same code:

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

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


I don't understand what this error means. When I look at the .tintColor method it list UIColor!? and I haven't found what the !? together means in Swift yet.


回答1:


This will solve your problem:

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

You can also

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



回答2:


The easiest way I have found is:

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



回答3:


This code works fine with latest version of Swift as on August 2019 (Swift 3.0)

Here this code I have implemented is the extension for the Segment control and can be used for all the segment controls in the application, where the set of code has to defined in application class.

Extension method can be used directly in the application, also you can add all the settings to same method or different methods in 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!
    }
}

Everywhere for the segments the below code can be used

 self.mySegment.setSegmentStyle()




回答4:


For changing the tintColor of the selected segment

Use the value changed event for the UISegmentControl to sort the segments in order by their origin x value, then loop and compare the selectedSegmentIndex property. Here is an example with assuming a 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 the tintColor for the initially selected segment, in this case it is the first:

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



回答5:


After analyzing and trying lots of answers to this and other similar questions I realized that with a 3rd-party custom segmented control it will be much easier and safer to do customizations than trying to hack Apple's UISegmentedControl.

Here's an example of customization with XMSegmentedControl (Swift 3).

Some in code:

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

And some in the Interface Builder (can be done in code too if you want):

The result is:

In my case it looks very much like system one, but still there are minor differences I had to do exactly as designer wanted it to be.

Note that XMSegmentedControl doesn't allow to have different background colors for different segments, but you can easily add this if needed, since it is a simple .swift file, which is very easy to understand and modify.




回答6:


sender.subviews.sort doesn't work in Swift 4 and remove border is referenced on How to remove border from 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)
}



回答7:


The solution is only for two segments but it could be easily extended to use for as much as you need. Firstly I will suggest to create an enum:

    enum SegmentedSections: Int { 
      case first, 
      case second
    }

Than create a funciton, and call this function in viewDidLoad, and also each time call it when .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
            }
        }
    }
}

Also you will need to change 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)
    }
}

Also, you will need to have an extension for UIImage. You can find it here.




回答8:


class MyUISegmentedControl: UISegmentedControl {

    required init(coder aDecoder: NSCoder){
        super.init(coder: aDecoder)!
        for subViewOfSegment: UIView in subviews {
            subViewOfSegment.tintColor = UIColor.red
        }
    }
}


来源:https://stackoverflow.com/questions/29312447/how-to-set-uisegmentedcontrol-tint-color-for-individual-segment

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!