Skip to content

Instantly share code, notes, and snippets.

@Catherine-K-George
Created June 9, 2021 18:11
Show Gist options
  • Save Catherine-K-George/065b6fedb87b21af4a9e41b80675e841 to your computer and use it in GitHub Desktop.
Save Catherine-K-George/065b6fedb87b21af4a9e41b80675e841 to your computer and use it in GitHub Desktop.
UISegmentControl with underline
extension UISegmentedControl {
private var underlineWidth: CGFloat { 20 }
private var underlineHeight: CGFloat { 2 }
private var segmentWidth: CGFloat {
bounds.width / CGFloat(numberOfSegments)
}
private var segmentMinX: CGFloat {
segmentWidth * CGFloat(selectedSegmentIndex)
}
private var underlineMinX: CGFloat {
segmentMinX + (segmentWidth/2) - (underlineWidth/2)
}
private var underlineMinY: CGFloat {
bounds.height - 1.0
}
func setup() {
style()
transparentBackground()
addUnderline()
}
func style() {
clipsToBounds = false
tintColor = .clear
backgroundColor = .clear
if #available(iOS 13.0, *) {
selectedSegmentTintColor = .clear
}
selectedSegmentIndex = 0
setTitleTextAttributes([.font: UIFont.boldSystemFont(ofSize: 15), .foregroundColor: UIColor.black], for: .selected)
setTitleTextAttributes([.font: UIFont.systemFont(ofSize: 14), .foregroundColor: UIColor.darkGray], for: .normal)
sizeToFit()
}
func transparentBackground() {
let backgroundImage = UIImage.coloredRectangleImageWith(color: UIColor.clear.cgColor, andSize: self.bounds.size)
let dividerImage = UIImage.coloredRectangleImageWith(color: UIColor.clear.cgColor, andSize: CGSize(width: 1, height: self.bounds.height))
setBackgroundImage(backgroundImage, for: .normal, barMetrics: .default)
setBackgroundImage(backgroundImage, for: .selected, barMetrics: .default)
setBackgroundImage(backgroundImage, for: .highlighted, barMetrics: .default)
setDividerImage(dividerImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
}
func addUnderline() {
let underlineFrame = CGRect(x: underlineMinX, y: underlineMinY, width: underlineWidth, height: underlineHeight)
let underline = UIView(frame: underlineFrame)
underline.backgroundColor = UIColor.black
underline.tag = 1
self.addSubview(underline)
}
func setSelectedSegmentUnderline() {
guard let underline = self.viewWithTag(1) else {return}
UIView.animate(withDuration: 0.1, animations: {
underline.frame.origin.x = self.underlineMinX
})
}
}
// MARK: - UIImage extension
extension UIImage {
class func coloredRectangleImageWith(color: CGColor, andSize size: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
let graphicsContext = UIGraphicsGetCurrentContext()
graphicsContext?.setFillColor(color)
let rectangle = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
graphicsContext?.fill(rectangle)
let rectangleImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return rectangleImage!
}
}
@Catherine-K-George
Copy link
Author

Usage:
segment

class ViewController: UIViewController {

    @IBOutlet weak var segment: UISegmentedControl!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        segment.setup()
    }
    
    @IBAction func segmentValueChanged(_ sender: UISegmentedControl) {
        sender.setSelectedSegmentUnderline()
    }
    
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment