0

I've used this extension for the UISegmentedControl which works as you can see here.

But I want to UISegementedControl to work slightly differently. When I select a segment, I want the selected segment's image to change color to colorGreyLight instead of having the background color change to colorGreyDark and the selected segement image change to UIColor.clearColor() (as you can see here)

So how can I do this?

My Code

UISegmented Control Extension:

extension UISegmentedControl {
    func removeBorders() {
        setBackgroundImage(imageWithColor(UIColor.clearColor()), 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
    }
}

UISegemented Control:

    let types = ["rectangle", "circle", "triangle"]
    shapeSelector = UISegmentedControl(items: types)
    shapeSelector.frame = CGRectMake(0, 0, sliderHeight*3 + 30, sliderHeight)
    shapeSelector.center = CGPoint(x: drawToolbar.bounds.width/2, y: sliderCenterY)
    shapeSelector.tintColor = colorGreyDark
    shapeSelector.removeBorders()
    shapeSelector.selectedSegmentIndex = 0 //default: select rectangle
    shapeSelector.addTarget(self, action: "selectShape:", forControlEvents: .ValueChanged)
    shapeSelector.setImage(UIImage(named: "rectangle"), forSegmentAtIndex: 0)
    shapeSelector.setImage(UIImage(named: "circle"), forSegmentAtIndex: 1)
    shapeSelector.setImage(UIImage(named: "triangle"), forSegmentAtIndex: 2)
    shapeSelector.contentMode = UIViewContentMode.ScaleAspectFit
    drawToolbar.addSubview(shapeSelector)

If it's any concern I'm using:

  • IOS 9.2
  • Swift 2
  • Xcode 7.2

UPDATE Okay so I've changed my code (as marked with comments below) as suggested by Keyur

UISegmented Control Extension:

extension UISegmentedControl {
    func removeBorders() {
        setBackgroundImage(imageWithColor(UIColor.clearColor()), forState: .Normal, barMetrics: .Default)
        setBackgroundImage(imageWithColor(UIColor.clearColor()), forState: .Selected, barMetrics: .Default) //change to clear color
        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
    }
}

UISegemented Control:

    let types = ["rectangle", "circle", "triangle"]
    shapeSelector = UISegmentedControl(items: types)
    shapeSelector.frame = CGRectMake(0, 0, sliderHeight*3 + 30, sliderHeight)
    shapeSelector.center = CGPoint(x: drawToolbar.bounds.width/2, y: sliderCenterY)
    shapeSelector.tintColor = colorGreyDark
    shapeSelector.removeBorders()
    shapeSelector.selectedSegmentIndex = 0 //default: select rectangle
    (shapeSelector.subviews[0] as UIView).tintColor = colorGreyLight //added this line
    shapeSelector.addTarget(self, action: "selectShape:", forControlEvents: .ValueChanged)
    shapeSelector.setImage(UIImage(named: "rectangle"), forSegmentAtIndex: 0)
    shapeSelector.setImage(UIImage(named: "circle"), forSegmentAtIndex: 1)
    shapeSelector.setImage(UIImage(named: "triangle"), forSegmentAtIndex: 2)
    shapeSelector.contentMode = UIViewContentMode.ScaleAspectFit
    drawToolbar.addSubview(shapeSelector)

selectShape() function:

func selectShape(sender: UISegmentedControl){
    switch sender.selectedSegmentIndex{
    case 0: //rectangle
        shapeType = "rectangle"
        (sender.subviews[0] as UIView).tintColor = colorGreyLight
        (sender.subviews[1] as UIView).tintColor = colorGreyDark
        (sender.subviews[2] as UIView).tintColor = colorGreyDark
    case 1: //circle
        shapeType = "circle"
        (sender.subviews[0] as UIView).tintColor = colorGreyDark
        (sender.subviews[1] as UIView).tintColor = colorGreyLight
        (sender.subviews[2] as UIView).tintColor = colorGreyDark
    case 2: //triangle
        shapeType = "triangle"
        (sender.subviews[0] as UIView).tintColor = colorGreyDark
        (sender.subviews[1] as UIView).tintColor = colorGreyDark
        (sender.subviews[2] as UIView).tintColor = colorGreyLight
    default:
        shapeType = "rectangle"
        (sender.subviews[0] as UIView).tintColor = colorGreyLight
        (sender.subviews[1] as UIView).tintColor = colorGreyDark
        (sender.subviews[2] as UIView).tintColor = colorGreyDark
    }
}

Except when I try it, the selected shape is not always the one highlighted as you can see here. It seems to be almost randomly highlighting the shapes and I don't understand why.

Any help on this would be greatly appreciated!

Community
  • 1
  • 1
14wml
  • 4,048
  • 11
  • 49
  • 97

3 Answers3

3
(shapeSelector.subviews[2] as UIView).tintColor = UIColor .redColor()
(shapeSelector.subviews[1] as UIView).tintColor = UIColor .redColor()
(shapeSelector.subviews[0] as UIView).tintColor = UIColor .redColor()
Keyur Hirani
  • 1,607
  • 14
  • 22
  • I've changed my code as you suggested. Thank-you for that. Except now the selected shape is not always the one highlighted. Do you know why that would be? – 14wml Dec 30 '15 at 07:34
1
  1. set colors in your removeborders() function.

setBackgroundImage(imageWithColor(UIColor.clearColor()), forState: .Normal, barMetrics: .Default) setBackgroundImage(imageWithColor(UIColor.lightGrayColor()), forState: .Selected, barMetrics: .Default)

0

I've found my answer thanks to this post.

Apparently selected index is not a reliable way to assign tint color. Instead I had to keep track of the segments myself.

So that's what I did after I created my UISegmentedControl shapeSelector:

var segments: [UIView] = [UIView]()
for i in 0...shapeSelector.subviews.count-1{
    segments.append(shapeSelector.subviews[i])
}

And in my UISegmentedControl's function I did:

func selectShape(sender: UISegmentedControl){
    let i = sender.selectedSegmentIndex
    for s in segments{
        s.tintColor = colorGreyDark
    }
    segments[i].tintColor = colorGreyLight

    switch i{
    case 0:
        shapeType = "rectangle"
    case 1:
        shapeType = "circle"
    case 2:
        shapeType = "triangle"
    default:
        shapeType = "rectangle"
    }
}

Now everything works perfectly!


Full Code

extension UISegmentedControl {
    func removeBorders() {
        setBackgroundImage(imageWithColor(UIColor.clearColor()), forState: .Normal, barMetrics: .Default)
        setBackgroundImage(imageWithColor(UIColor.clearColor()), 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
    }
}

class DrawViewController: UIViewController {

    var shapeSelector: UISegmentedControl = UISegmentedControl()
    var segments: [UIView] = [UIView]()

    override func viewDidLoad() {
        super.viewDidLoad()

        //set up shape selector
        let types = ["rectangle", "circle", "triangle"]
        shapeSelector = UISegmentedControl(items: types)
        shapeSelector.frame = CGRectMake(shapeTypeLabel.frame.maxX + sliderSpace, 0, sliderHeight*3 + 30, sliderHeight)
        shapeSelector.center.y = shapeTypeLabel.center.y
        shapeSelector.tintColor = colorGreyDark
        shapeSelector.removeBorders()
        shapeSelector.addTarget(self, action: "selectShape:", forControlEvents: .ValueChanged)
        shapeSelector.setImage(UIImage(named: "rectangle"), forSegmentAtIndex: 0)
        shapeSelector.setImage(UIImage(named: "circle"), forSegmentAtIndex: 1)
        shapeSelector.setImage(UIImage(named: "triangle"), forSegmentAtIndex: 2)
        for i in 0...shapeSelector.subviews.count-1{
            segments.append(shapeSelector.subviews[i])
        }
        shapeSelector.selectedSegmentIndex = 0 //default: select rectangle
        segments[0].tintColor = colorGreyLight
        shapeSelector.contentMode = UIViewContentMode.ScaleAspectFit
        drawToolbar.addSubview(shapeSelector)
    }

    func selectShape(sender: UISegmentedControl){
        let i = sender.selectedSegmentIndex
        for s in segments{
            s.tintColor = colorGreyDark
        }
        segments[i].tintColor = colorGreyLight

        switch i{
        case 0:
            shapeType = "rectangle"
        case 1:
            shapeType = "circle"
        case 2:
            shapeType = "triangle"
        default:
            shapeType = "rectangle"
        }
    }
}
Community
  • 1
  • 1
14wml
  • 4,048
  • 11
  • 49
  • 97