8

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.

Deepak Sharma
  • 5,577
  • 7
  • 55
  • 131

2 Answers2

13

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()!)!
    }
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • 1
    Ok why size 32 for UIImage? Is that a fixed size that will work for all Segment controllers? – Deepak Sharma Aug 12 '19 at 06:38
  • It results in a segmented control that is the same height as a regular segmented control. – rmaddy Aug 12 '19 at 06:45
  • I tried a resizedImageWithCapInsets of size 1x1, but strangely, it restricts the text to be of size 1x1 pixel it seems. Now only issue is if this hardcoded size will continue to work or not. – Deepak Sharma Aug 12 '19 at 06:51
  • You can use a 1x1 image but then you need to set the segmented control's height such as `seg.frame.size.height = 32`. – rmaddy Aug 12 '19 at 06:54
  • How could this work with a Segmented Control using Storyboards? – GarySabo Aug 27 '19 at 18:12
1

to make the background of your UISegmentedControl transparent you can try this:

segmentedControl.backgroundColor = .clear
segmentedControl.setBackgroundImage(UIImage(), for: .normal, barMetrics: .default)
igor
  • 691
  • 5
  • 7