Ios – UISegmentedControl iOS 13 clear color

iosios13swiftuikituisegmentedcontrol

On iOS 12, to get a UISegmentedControl with clear border, clear divider line, everything clear was easy. All I did was this:

  settingControl.tintColor = .clear

   let font = myFont
   let boldfont = myBoldFont

  settingControl.setTitleTextAttributes([NSAttributedString.Key.foregroundColor : UIColor.white, NSAttributedString.Key.font:font], for: .normal)
  settingControl.setTitleTextAttributes([NSAttributedString.Key.foregroundColor : UIColor.red, NSAttributedString.Key.font:boldfont], for: .selected)

And then UISegmentedControl was full clear color (divider line, background, border)

But in iOS 13, I can not get it fully clear. I can set

settingControl.selectedSegmentTintColor = UIColor.clear

But it still does not clear the backgroundColor and divider line.

I tried setting backgroundColor to clear, but no effect.

 settingControl.backgroundColor = UIColor.clear

I also tried setting a clear image but still nothing:

 public extension UIImage {

  /**
   Returns image with size 1x1px of certain color.
   */
 class func imageWithColor(color : UIColor) -> UIImage? {
    let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
    UIGraphicsBeginImageContext(rect.size)
    let context = UIGraphicsGetCurrentContext()

    context?.setFillColor(color.cgColor)

    context?.fill(rect)

    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return image
}

 }

And then this:

  let clearImage = UIImage.imageWithColor(color: UIColor.clear)
    settingControl.setDividerImage(clearImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)


   settingControl.setBackgroundImage(clearImage, for: .normal, barMetrics: .default)
   settingControl.setBackgroundImage(clearImage, for: .selected, barMetrics: .default)

This is how it looks like on iOS 12. On iOS 13, this seems impossible.

This is how it looks like on iOS 12. On iOS 13, this seems impossible.

Best Answer

Here's a way to replicate that plain segmented control in iOS 13:

import UIKit
import PlaygroundSupport

class PlainSegmentedControl: UISegmentedControl {
    override init(items: [Any]?) {
        super.init(items: items)

        setup()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // Used for the unselected labels
    override var tintColor: UIColor! {
        didSet {
            setTitleTextAttributes([.foregroundColor: tintColor!, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .normal)
        }
    }

    // Used for the selected label
    override var selectedSegmentTintColor: UIColor? {
        didSet {
            setTitleTextAttributes([.foregroundColor: selectedSegmentTintColor ?? tintColor!, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .selected)
        }
    }

    private func setup() {
        backgroundColor = .clear

        // Use a clear image for the background and the dividers
        let tintColorImage = UIImage(color: .clear, size: CGSize(width: 1, height: 32))
        setBackgroundImage(tintColorImage, for: .normal, barMetrics: .default)
        setDividerImage(tintColorImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)

        // Set some default label colors
        setTitleTextAttributes([.foregroundColor: UIColor.black, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .normal)
        setTitleTextAttributes([.foregroundColor: tintColor!, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .selected)
    }
}

Here's some test code to put in a playground:

// Create a dark green view as a test background
let bg = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 100))
bg.backgroundColor = UIColor(red: 0.224, green: 0.408, blue: 0.467, alpha: 1)

// The plain segmented control
let seg = PlainSegmentedControl(items: ["Number One", "Number Two", "Number Three"])
seg.tintColor = .white
seg.selectedSegmentTintColor = .green
seg.selectedSegmentIndex = 0
bg.addSubview(seg)
PlaygroundPage.current.liveView = bg

Here's the UIImage extension to create a sized image from a color:

extension UIImage {
    convenience init(color: UIColor, size: CGSize) {
        UIGraphicsBeginImageContextWithOptions(size, false, 1)
        color.set()
        let ctx = UIGraphicsGetCurrentContext()!
        ctx.fill(CGRect(origin: .zero, size: size))
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        self.init(data: image.pngData()!)!
    }
}