How to use a UIButton as a toggle switch

Viewed 64082

I am using a UIButton of custom type and what I want is use it like a toggle switch with the change of image. Like when it is clicked if previously it was not in selected mode it should go in selected mode or otherwise vice-a-versa. Also it will have a different image and when it is selected it will have a different image when it is not.

I am not able to do it programatically, is there any good easy way to do this.

11 Answers

In the interface:

@interface TransportViewController : UIViewController {

    UIButton *button;
}
@property(nonatomic, retain) UIButton *button;

In the implementation:

- (void)loadView {

[super loadView];

    ...

    [self setButton:[UIButton buttonWithType:UIButtonTypeCustom]];
    [button addTarget:self action:@selector(onClick:) forControlEvents:UIControlEventTouchUpInside];
    [button setImage:[UIImage imageNamed:@"image1"] forState:UIControlStateNormal];
    [button setImage:[UIImage imageNamed:@"image2"] forState:UIControlStateSelected];
}

- (void) onClick:(UIButton *)sender {

    [sender setSelected:!sender.selected];
}

In order to do so we can use UIButton Subclass:

class UIToggleButton: UIButton {
    fileprivate let onImage: UIImage
    fileprivate let offImage: UIImage
    fileprivate let target: AnyObject
    fileprivate let onAction: Selector
    fileprivate let offAction: Selector
    var isOn: Bool {
        didSet {
            let image = isOn ? onImage : offImage
            setImage(image, for: UIControlState())
        }
    }

    init(onImage: UIImage,
        offImage: UIImage,
        target: AnyObject,
        onAction: Selector,
        offAction: Selector)
    {
        isOn = false
        self.onImage = onImage
        self.offImage = offImage
        self.target = target
        self.onAction = onAction
        self.offAction = offAction
        super.init(frame: CGRect.zero)
        setImage(offImage, for: UIControlState())
        addTarget(self, action: #selector(UIToggleButton.tapAction), for: .touchUpInside)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    @objc func tapAction() {
        let sel = isOn ? onAction : offAction
        isOn = !isOn
        _ = target.perform(sel)
    }
}

My implementation of a UIButton as a Switch.


class ButtonSwitch: UIButton {
  override func sendAction(_ action: Selector, to target: Any?, for event: UIEvent?) {
    if allControlEvents == .touchUpInside {
      isSelected.toggle()
    }
    super.sendAction(action, to: target, for: event)
  }
}
Related