How do I remove the outside border of a segmented control? I've set the divider image to what I wanted but now to follow the mock of my app I need to have a segmented control without the outer border.
9 Answers
What you must understand is the backgroundColor property is not stateful. 
Hence you have to use setBackgroundImage(_:for:barMetrics:). 
We can easily remove both borders and dividers using the below function.
For Swift 3 & 4+:
extension UISegmentedControl {
    func removeBorders() {
        setBackgroundImage(imageWithColor(color: backgroundColor ?? .clear), for: .normal, barMetrics: .default)
        setBackgroundImage(imageWithColor(color: tintColor!), for: .selected, barMetrics: .default)
        setDividerImage(imageWithColor(color: UIColor.clear), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
    }
    // 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!
    }
}
For Swift 2.2:
extension UISegmentedControl {
    func removeBorders() {
        setBackgroundImage(imageWithColor(backgroundColor!), forState: .Normal, barMetrics: .Default)
        setBackgroundImage(imageWithColor(tintColor!), forState: .Selected, barMetrics: .Default)
        setDividerImage(imageWithColor(UIColor.clearColor()), forLeftSegmentState: .Normal, rightSegmentState: .Normal, barMetrics: .Default)
    }
    // create a 1x1 image with this color
    private func imageWithColor(color: UIColor) -> UIImage {
        let rect = CGRectMake(0.0, 0.0, 1.0, 1.0)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        CGContextSetFillColorWithColor(context, color.CGColor);
        CGContextFillRect(context, rect);
        let image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return image
    }
}
Call the above function.
segmentedControl.removeBorders()
Reference: Remove UISegmentedControl separators completely. (iphone)
Thanks to https://stackoverflow.com/users/3921490/amagain for Swift 3 version.
- 9,404
 - 1
 - 31
 - 57
 
- 
                    Thanks :) It worked =D But one more question, this will make my segmented control have a sharp rectangular corner, any ways to make it rounded? – Happiehappie Jul 28 '15 at 03:33
 - 
                    @Happiehappie no you can't, please refer to this answer http://stackoverflow.com/questions/1834244/uisegmentedcontrol-without-rounded-corner – Sohil R. Memon Jul 28 '15 at 06:51
 - 
                    I am getting `fatal error: unexpectedly found nil while unwrapping an Optional value` on line `setBackgroundImage(imageWithColor(color: backgroundColor!), for: .normal, barMetrics: .default)` – Kakaji May 30 '17 at 09:33
 - 
                    You also need to set background color to some color other that `Default` apparently. `backgroundColor` was nil when it was set to `Default`. – Kakaji May 30 '17 at 09:39
 - 
                    3To fix the background nil issue: `setBackgroundImage(imageWithColor(color: backgroundColor ?? .white), for: .normal, barMetrics: .default)` – Whoa Oct 18 '17 at 13:48
 - 
                    Doesn't work anymore on iOS13! Have a look at this question - https://stackoverflow.com/questions/57450865/uisegmentedcontrol-ios-13-clear-color – Deepak Sharma Aug 11 '19 at 14:46
 
Here's the swift 3 version of Sohil's answer that might help someone else. It did help me. :)
extension UISegmentedControl {
func removeBorders() {
    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)
}
// 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!
    }
}
Hope it will help someone
Swift - 4
Make the Background color and Tint color of your Segment control to same color. Then "set titleTextAttributes" of your Segment control
    segmentedControl.tintColor = UIColor.red
    segmentedControl.backgroundColor = UIColor.red
    let attributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
    segmentedControl.setTitleTextAttributes(attributes, for: .normal)
    segmentedControl.setTitleTextAttributes(attributes, for: .selected)
- 884
 - 1
 - 15
 - 22
 
- 
                    1
 - 
                    Yea correct. This is trick when the backgroundColor and Tint color is same then the borderColor will be same color as TintColor. – kalpa Apr 02 '19 at 09:10
 
If you want save borders between cells
extension UISegmentedControl {
  func removeBorders() {
    if let backgroundColor = backgroundColor, let backgroundImage = UIImage.imageWithSize(size: CGSize.one_one, color: backgroundColor){
      setBackgroundImage(backgroundImage, for: .normal, barMetrics: .default)
    }
    if let tintColor = tintColor, let tintImage = UIImage.imageWithSize(size: CGSize.one_one, color: tintColor){
      setBackgroundImage(tintImage, for: .selected, barMetrics: .default)
        setDividerImage(tintImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
    }
  }
}
extension CGSize{
  static var one_one: CGSize{
    return CGSize(width: 1.0, height: 1.0)
  }
}
extension UIImage{
  static func imageWithSize(size : CGSize, color : UIColor = UIColor.white) -> UIImage? {
    var image:UIImage? = nil
    UIGraphicsBeginImageContext(size)
    if let context = UIGraphicsGetCurrentContext() {
      context.setFillColor(color.cgColor)
      context.addRect(CGRect(origin: CGPoint.zero, size: size));
      context.drawPath(using: .fill)
      image = UIGraphicsGetImageFromCurrentImageContext();
    }
    UIGraphicsEndImageContext()
    return image
  }
}
- 2,747
 - 10
 - 38
 - 53
 
- 363
 - 3
 - 9
 
You might have the usecase where you don't want the rounded border as you don't want to see it if it's embedded in a cell. In this case, set the autolayout constraints to -2 and the border will be hidden as it will extend beyond the cell border.
- 336
 - 8
 - 21
 - 41
 
If you need segment control with texts Only, use,
segmentControl.backgroundColor = .clear
segmentControl.tintColor = .clear
let attributes: [NSAttributedString.Key : Any] = [.font : UIFont(family: .medium, ofSize: 13)!, .foregroundColor : UIColor.white]
segmentControl.setTitleTextAttributes(attributes, for: .normal)
let selectedAttrib: [NSAttributedString.Key : Any] = [.font : UIFont(family: .medium, ofSize: 13)!, .foregroundColor : UIColor.red]
segmentControl.setTitleTextAttributes(hightLightedStateAttrib, for: .selected)
NB: I googled it for a long time, thats why i'm posted here.
Source: CodeMentor
- 15,485
 - 6
 - 64
 - 84
 
- The accepted answer works for getting rid of the border.
 - The solution mentioned here also works for disabling the segmented Control.
 
Yet putting the two solutions together, I wasn't able to get the correct selected segment  in a disabled state. 
What I wanted was that upon selecting a segment and making a network call, I wanted to disable the segmented control.
The outcome was like this:
What was desired was this:
The only addition to Sohil's solution is:
setBackgroundImage(imageWithColor(color: imageWithColor(color: tintColor)), for: [.selected, .disabled], barMetrics: .default)
After the selected && disabled segment will have the right color.
- 33,269
 - 19
 - 164
 - 293
 
Swift 5.x:
This solution remove only the external border and preserve the round corner on each button
extension UISegmentedControl {
    func removeBorders(andBackground:Bool=false) {
        setBackgroundImage(imageWithColor(color: backgroundColor ?? .clear), for: .normal, barMetrics: .default)
        setBackgroundImage(imageWithColor(color: tintColor!), for: .selected, barMetrics: .default)
        setDividerImage(imageWithColor(color: UIColor.clear), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
        _ = self.subviews.compactMap {
            if ($0.frame.width>0) {
                $0.layer.cornerRadius = 8
                $0.layer.borderColor = UIColor.clear.cgColor
                $0.clipsToBounds = true
                $0.layer.borderWidth = andBackground ? 1.0 : 0.0
                $0.layer.borderColor = andBackground ? tintColor?.cgColor : UIColor.clear.cgColor
                andBackground ? $0.layer.backgroundColor = UIColor.clear.cgColor : nil
            }
        }
    }
    // 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!
    }
}
Usage:
mySegmentedControl.removeBorders()
- 34,887
 - 11
 - 106
 - 133
 
- 
                    
 - 
                    @RoneySampaio The purpose of this method was to remove the external round corners, have you read the title and the description? It re-create the round corner to each button inside.. – Alessandro Ornano Nov 01 '19 at 12:40
 
Sohil's answer did help me.
But if you don't set the UIImage size, it may affect the size of the UISegmentedControl.
If you also encounter this problem, please consider using the following code.
func *(lhs: CGSize, rhs: CGFloat) -> CGSize {
    return CGSize(width: lhs.width * rhs, height: lhs.height * rhs)
}
extension UIImage {
    func resized(_ size: CGSize) -> UIImage? {
        defer { UIGraphicsEndImageContext() }
        UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
        self.draw(in: CGRect(origin: .zero, size: size))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
    func resized(_ size: CGFloat) -> UIImage? {
        guard size > 0, self.size.width > 0, self.size.height > 0 else { return nil }
        let ratio = size / max(self.size.width, self.size.height)
        return self.resized(self.size * ratio)
    }
    func refilled(_ color: UIColor) -> UIImage? {
        defer { UIGraphicsEndImageContext() }
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        color.set()
        UIGraphicsGetCurrentContext()?.fill(CGRect(origin: .zero, size: self.size))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
    public convenience init?(color: UIColor = .clear, size: CGSize) {
        defer { UIGraphicsEndImageContext() }
        UIGraphicsBeginImageContext(size)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        context.setFillColor(color.cgColor);
        context.fill(CGRect(origin: .zero, size: size));
        guard let cgImage = UIGraphicsGetImageFromCurrentImageContext()?.cgImage else { return nil }
        self.init(cgImage: cgImage)
    }
}
extension UISegmentedControl {
    func removeBorders() {
        let image = UIImage(size: self.bounds.size)
        self.setBackgroundImage(image, for: .normal, barMetrics: .default)
        self.setBackgroundImage(image?.refilled(self.tintColor), for: .selected, barMetrics: .default)
        self.setDividerImage(image?.resized(1), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
    }
}
Easy to use:
segmentedControl.removeBorders()
- 6,562
 - 1
 - 36
 - 30
 

