22

Is there a way to completely remove the line separating the two segments in a UISegmentedControl?

Setting the segmentedControlStyle is not helping.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Kazmi
  • 593
  • 1
  • 6
  • 24

9 Answers9

34

If anybody wants this kind of UISegmentedControl View-

enter image description here

EDITED:- Swift 3.0 extensions

    extension UISegmentedControl {

    func customizeAppearance(for height: Int) {

        setTitleTextAttributes([NSFontAttributeName:UIFont(name:"Helvetica Neue", size:13.0)!,NSForegroundColorAttributeName:UIColor.white], for:.normal)
        setTitleTextAttributes([NSFontAttributeName:UIFont(name:"Helvetica Neue", size:13.0)!,NSForegroundColorAttributeName:UIColor.white], for:.selected)
        setDividerImage(UIImage().colored(with: .clear, size: CGSize(width: 1, height: height)), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
        setBackgroundImage(UIImage().colored(with: .clear, size: CGSize(width: 1, height: height)), for: .normal, barMetrics: .default)
        setBackgroundImage(UIImage().colored(with: UIColor.init(red: 215/255.0, green: 0.0, blue: 30/255.0, alpha: 1.0), size: CGSize(width: 1, height: height)), for: .selected, barMetrics: .default);

        for  borderview in subviews {
            let upperBorder: CALayer = CALayer()
            upperBorder.backgroundColor = UIColor.init(red: 215/255.0, green: 0.0, blue: 30/255.0, alpha: 1.0).cgColor
            upperBorder.frame = CGRect(x: 0, y: borderview.frame.size.height-1, width: borderview.frame.size.width, height: 1)
            borderview.layer.addSublayer(upperBorder)
        }

    }
}

extension UIImage {

    func colored(with color: UIColor, size: CGSize) -> UIImage {
        UIGraphicsBeginImageContext(size)
        let context = UIGraphicsGetCurrentContext()
        context!.setFillColor(color.cgColor);
        let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: size)
        context!.fill(rect);
        let image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return image!
    }
}

The UIImage extension generates a colored image with desired size.

Forcing the height parameter in customizeAppearance avoid any crash when building the context.

You can make it even more reusable by extracting each customization attribute and put it as function's parameters ;)

Here is sample code, tested over iOS 9 and works fine for me.

Add these lines of code in viewDidLoad-

[yourSegmentControl setTitleTextAttributes:@{ NSFontAttributeName:[UIFont fontWithName:@"Roboto-black" size:13.0],NSForegroundColorAttributeName:[UIColor whiteColor] }forState:UIControlStateSelected];

[yourSegmentControl setTitleTextAttributes:@{ NSFontAttributeName:[UIFont fontWithName:@"Roboto-black" size:13.0],NSForegroundColorAttributeName:[UIColor whiteColor] }forState:UIControlStateNormal];

[yourSegmentControl setDividerImage:[self imageWithColor:[UIColor clearColor]] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

[yourSegmentControl setBackgroundImage:[self imageWithColor:[UIColor clearColor]] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

[yourSegmentControl setBackgroundImage:[self imageWithColor:[UIColor colorWithRed:215/255.0 green:0 blue:30/255.0 alpha:1.0]] forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];

for (UIView *borderview in yourSegmentControl.subviews) {

    CALayer *upperBorder = [CALayer layer];

    upperBorder.backgroundColor = [UIColor colorWithRed:215/255.0 green:0 blue:30/255.0 alpha:1.0].CGColor;

    upperBorder.frame = CGRectMake(0, borderview.frame.size.height-1, borderview.frame.size.width, 1.0f);

    [borderview.layer addSublayer:upperBorder];
}

and

- (UIImage *)imageWithColor:(UIColor *)color {
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}

Here is the Swift extension for achieving same view in Swift-

yourSegmentControl.setTitleTextAttributes([NSFontAttributeName:UIFont(name:"Helvetica Neue", size:13.0)!,NSForegroundColorAttributeName:UIColor.whiteColor()], forState:UIControlState.Normal)

yourSegmentControl.setTitleTextAttributes([NSFontAttributeName:UIFont(name:"Helvetica Neue", size:13.0)!,NSForegroundColorAttributeName:UIColor.whiteColor()], forState:UIControlState.Selected)

yourSegmentControl.setDividerImage(self.imageWithColor(UIColor.clearColor()), forLeftSegmentState: UIControlState.Normal, rightSegmentState: UIControlState.Normal, barMetrics: UIBarMetrics.Default)

yourSegmentControl.setBackgroundImage(self.imageWithColor(UIColor.clearColor()), forState:UIControlState.Normal, barMetrics:UIBarMetrics.Default)

yourSegmentControl.setBackgroundImage(self.imageWithColor(UIColor.init(red: 215/255.0, green: 0.0, blue: 30/255.0, alpha:1.0)), forState:UIControlState.Selected, barMetrics:UIBarMetrics.Default);

for  borderview in yourSegmentControl.subviews {

let upperBorder: CALayer = CALayer()
upperBorder.backgroundColor = UIColor.init(red: 215/255.0, green: 0.0, blue: 30/255.0, alpha: 1.0).CGColor
upperBorder.frame = CGRectMake(0, borderview.frame.size.height-1, borderview.frame.size.width, 1.0);
borderview.layer .addSublayer(upperBorder);

}

and

func imageWithColor(color: UIColor) -> UIImage {

    let rect = CGRectMake(0.0, 0.0, 1.0, yourSegmentControl.frame.size.height)
    UIGraphicsBeginImageContext(rect.size)
    let context = UIGraphicsGetCurrentContext()
    CGContextSetFillColorWithColor(context, color.CGColor);
    CGContextFillRect(context, rect);
    let image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image

}
Tib
  • 1,250
  • 13
  • 20
Rohit Khandelwal
  • 1,778
  • 15
  • 23
23

Use this method to change your segment divider image:

[segmentControl setDividerImage:dividerimg
            forLeftSegmentState:UIControlStateNormal
              rightSegmentState:UIControlStateNormal
                     barMetrics:UIBarMetricsDefault];
enjayem
  • 941
  • 8
  • 21
Naveed
  • 1,979
  • 1
  • 13
  • 20
21

I combined the previous answers into a Swift extension.

I wanted to remove all borders and dividers. This code just uses the normal segment colors, e.g. tint and background for selected / deselected.

Call

segmentedControl.removeBorders()

Here's the extension

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
    }
}
n13
  • 6,843
  • 53
  • 40
  • 3
    I had to use explicit colors in lieu of `backgroundColor!` and `tintColor!`, otherwise you may find nil while unwrapping. Otherwise, brilliant! – slider Sep 29 '15 at 22:56
  • @dperk Good point if the code is generic it should handle background and tint set to nil. These could either be an argument to removeBorders() or I make defaults when they're not set. Not sure how the control finds defaults for these when not set but could find out & do the same. For now make sure tintColor and backgroundColor are set ;) – n13 Sep 30 '15 at 02:40
  • 1
    Question: everytime I tap a segment, I get a light gray rectangle in the background of that segment. It only appears as I'm tapping and disappears after the tap. It looks pretty ugly. How would I remove this? – slider Oct 01 '15 at 07:45
  • 1
    By calling setBackgroundImage with: imageWithColor(UIColor.clearColor() ) for the .Highlighted state. – GK100 Aug 03 '16 at 15:51
  • I am currently doing this, and I am having an issue. If I EVER call setBackgroundImage for the Normal state, and I try to PROGRAMMATICALLY change the selected index of the UISegmentedControl, the icons' tint does NOT update. Only the highlighting color updates. Therefore you have this dim icon that you can barely see. Has anybody else seen or fixed this? – datWooWoo Nov 16 '16 at 17:10
14

The following code will do exactly what you want.

UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, self.segControlOut.frame.size.height), NO, 0.0);
UIImage *blank = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.segControlOut setDividerImage:blank
                forLeftSegmentState:UIControlStateNormal
                  rightSegmentState:UIControlStateNormal
                         barMetrics:UIBarMetricsDefault];
Zia
  • 14,622
  • 7
  • 40
  • 59
10

You can remove all background, border and separators from a UISegmentedControl by setting a black image. Or you can set custom colours.

The below example removes all borders/seperators, and sets the background to be white with 0.2 alpha, and the selected segment to be white with alpha 1.0

[self.segmentedControl setBackgroundImage:[self imageWithColor:[UIColor colorWithWhite:1.0 alpha:0.2]] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:[self imageWithColor:[UIColor colorWithWhite:1.0 alpha:1.0]] forState:UIControlStateSelected  barMetrics:UIBarMetricsDefault];

- (UIImage *)imageWithColor:(UIColor *)color {
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}
A.Badger
  • 4,279
  • 1
  • 26
  • 18
  • I am currently doing this, and I am having an issue. If I EVER call setBackgroundImage for the Normal state, and I try to PROGRAMMATICALLY change the selected index of the UISegmentedControl, the icons' tint does NOT update. Only the highlighting color updates. Therefore you have this dim icon that you can barely see. Has anybody else seen or fixed this? – datWooWoo Nov 16 '16 at 17:13
6

I have used segmentcontrol.tintColor = [UIColor clearColor]; with iOS7 and it seems to work.

palaniraja
  • 10,432
  • 5
  • 43
  • 76
5

@naveed's and @Jon Setting's answers saved my day!

But as a bit of a perfectionist, i was frustrated to find out that this code also leaves holes in the outer border of the control:

Before

So I added a few lines of code to get rid of those and make it look neat: After

The complete code for this would be

CGFloat h = self.segControlOut.frame.size.height;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, h), NO, 0.0);

// draw the missing dots with the control border color
[self.segControlOut.tintColor set];
UIRectFrame( CGRectMake(0, -1, 1, 2.5) );
UIRectFrame( CGRectMake(0, h-1.5, 1, 2.5) );

UIImage *blank = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.segControlOut setDividerImage:blank
                forLeftSegmentState:UIControlStateNormal
                  rightSegmentState:UIControlStateNormal
                         barMetrics:UIBarMetricsDefault];
Pavel Lint
  • 3,252
  • 1
  • 18
  • 18
2

No, there is not. You should look into creating the UISegmentedControl functionality manually. Maybe use two UIButtons.

Michael Frederick
  • 16,664
  • 3
  • 43
  • 58
1
- (void) configSegmentControl {
    [segmentControl setBackgroundImage:[self imageWithColor:[UIColor blueColor]] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
    [segmentControl setBackgroundImage:[self imageWithColor:[UIColor redColor]] forState:UIControlStateSelected  barMetrics:UIBarMetricsDefault];
    segmentControl.layer.cornerRadius = 4.0f;
    segmentControl.clipsToBounds = YES;
}

- (UIImage *)imageWithColor:(UIColor *)color {
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}
Sargis
  • 1,196
  • 1
  • 18
  • 31