如何为单个段设置 UISegmentedControl Tint Color

How to set UISegmentedControl Tint Color for individual segment

开始学习 Swift 并尝试转换此 ObjectiveC 代码:

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

这正确设置了第一段的色调。


这是我最接近获得相同代码的 Swift 版本的版本:

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

我得到的错误是'@Ivalue $T9' is not identical to 'UIColor!!'


我不明白这个错误是什么意思。当我查看 .tintColor 方法时,它列出了 UIColor!?,但我还没有找到 !? 在 Swift 中的含义。

这将解决您的问题:

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

你也可以

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

用于更改所选段的 tintColor

使用 UISegmentControl 的值更改事件按其原始 x 值对段进行排序,然后循环并比较 selectedSegmentIndex 属性。这是一个假设 4 段的分段控制的示例:

@IBAction func indexChanged(sender: UISegmentedControl) {

    let sortedViews = sender.subviews.sort( { [=10=].frame.origin.x < .frame.origin.x } )

    for (index, view) in sortedViews.enumerate() {
        if index == sender.selectedSegmentIndex {
            view.tintColor = UIColor.blueColor()
        } else {
            view.tintColor = UIColor.lightGrayColor()
        }
    }

}

然后在 viewDidLoad 中为最初选择的段设置 tintColor,在本例中它是第一个:

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

我找到的最简单的方法是:

segmentControl.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.redColor()], forState: UIControlState.Selected)
class MyUISegmentedControl: UISegmentedControl {

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

此代码适用于 2019 年 8 月最新版本的 Swift (Swift 3.0)

这里我实现的这段代码是Segment控件的扩展,可以用于应用程序中的所有Segment控件,其中代码集必须在应用程序中定义class.

扩展方法可以直接在应用程序中使用,也可以将所有设置添加到扩展中的相同方法或不同方法class,如下所示。

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!
    }
}

可以在任何地方使用以下代码

 self.mySegment.setSegmentStyle()

在对这个问题和其他类似问题进行分析并尝试了很多答案之后,我意识到使用第 3 方自定义分段控件进行自定义比尝试破解 Apple 的 UISegmentedControl 更容易和更安全。

这是一个使用 XMSegmentedControl (Swift 3) 进行自定义的示例。

部分代码:

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

还有一些在 Interface Builder 中(如果需要,也可以在代码中完成):

结果是:

在我的例子中,它看起来非常像系统一,但仍然存在细微差别,我必须完全按照设计师的要求去做。

请注意,XMSegmentedControl 不允许不同的段使用不同的背景颜色,但如果需要,您可以轻松添加它,因为它是一个简单的 .swift 文件,非常容易理解和修改.

sender.subviews.sort 在 Swift 4 中不起作用,删除边框在

中被引用
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: { [=10=].originX < .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)
}

该解决方案仅适用于两个细分市场,但可以轻松扩展以根据需要使用。 首先,我建议创建一个枚举:

    enum SegmentedSections: Int { 
      case first, 
      case second
    }

然后创建一个函数,并在viewDidLoad中调用这个函数,并且每次在segmentedControl中发生.valueChanged时调用它:

func setProperSegmentedControlColoring(_ segment: UISegmentedControl, type: SegmentedSections) {
    setSeparatorImages(for: segment, with: type)
    let subviews = segment.subviews
    let sortedViews = subviews.sorted(by: { [=11=].frame.origin.x < .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
            }
        }
    }
}

此外,您还需要相应地更改分隔图像:

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)
    }
}

此外,您还需要 UIImage 的扩展。 You can find it here.

对于 Swift 5.1,我发现可以工作:

//To set Text Colour when Segment Selected
segmentOutlet.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.red], for: UIControl.State.selected)

//To Set Background Colour when Segment Selected,
//The number in the [] is the segment that gets value change
let subViewOfSegment: UIView = segmentOutlet.subviews[1] as UIView
        subViewOfSegment.backgroundColor = UIColor.blue

我将它们放在 Switch 语句中,用于在按下时捕获按钮的动作。

从iOS13开始,属性selectedSegmentTintColor可以用来设置段控件的tint颜色!

所以简单地做:

segmentControl.selectedSegmentTintColor = .red

如果支持以下iOS13,

   if #available(iOS 13.0, *) {
      segmentControl.selectedSegmentTintColor = .red
    } else {
      // Fallback on earlier versions
      // Solution posted by David can be used here
    }