How to use a UIButton as a toggle switch
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开发者_StackOverflow中文版 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.
I believe this post has a better solution : iPhone UIButton with UISwitch functionality
UIButton has toggling built in. There is a selected property that you can set and change the skins based on the state.
In your header file add:
IBOutlet UIButton *toggleButton;
BOOL toggleIsOn;
@property (nonatomic, retain) IBOutlet UIButton *toggleButton;
In the implementation:
- (IBACtion)toggle:(id)sender
{
if(toggleIsOn){
//do anything else you want to do.
}
else {
//do anything you want to do.
}
toggleIsOn = !toggleIsOn;
[self.toggleButton setImage:[UIImage imageNamed:toggleIsOn ? @"on.png" :@"off.png"] forState:UIControlStateNormal];
}
then link your button with the IBActions and the IBOutlet and initialize toggleIsOn
to NO.
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];
}
UIButton
does supports a "toggle" functionality by default. To use this you need to set a different image or even text color in Interface Builder for the State Configuration = Selected
, and use the selected property of UIButton
to toggle its state.
Code:
- (IBAction)yourButtonTouch:(UIButton *)sender {
sender.selected = !sender.selected;
if (sender.selected) {
//...
// Action to be performed when button is selected or
// the first touch
// ...
}
}
For Swift 3
@IBAction func playPause(sender : UIButton){
if sender.isSelected {
player.pause()
}else{
player.play()
}
sender.isSelected = !sender.isSelected
}
- (IBAction)buttonTapped:(UIButton *)sender {
//first time sender.selected is No
if (sender.selected) {
//code here
sender.selected=NO;
}
else{
//code here
sender.selected=YES;
}
}
The only problem here is that you have to use 2 images to achieve toggling. Also you can't use highlighted property because of UIButton (UIControl) automatically sets this property under the hood, to be exact in touchBegan:, touchMoved:, etc. methods. The best way I offer is to simple use subclassing:
@interface ToggleButton : UIButton
@end
@implementation ToggleButton
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
self.highlighted = self.selected = !self.selected;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesMoved:touches withEvent:event];
self.highlighted = self.selected;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesEnded:touches withEvent:event];
self.highlighted = self.selected;
}
- (void)setSelected:(BOOL)selected{
[super setSelected:selected];
self.highlighted = selected;
}
@end
This is quite enough to make your toggle working
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)
}
}
Change button image isn't a difficult task. And you can use some BOOL value to detect if your switch-button is in "ON" state. and in your onBtnClk method you can just change state of your BOOL value and set image for current state.
I made this class, changing the class to PGToggleButton in the Interface builder will do it. It uses the images for Default and Highlighted state, and has a public property to get/set the actual state.
PGToggleButton.h
@interface PGToggleButton : UIButton
@property (nonatomic, getter=isOn) BOOL on;
-(void)toggle;
@end
PGToggleButton.m
#import "PGToggleButton.h"
@interface PGToggleButton ()
@property (nonatomic, strong) UIImage *offStateImage;
@property (nonatomic, strong) UIImage *onStateImage;
-(void)touchedUpInside:(UIButton*) sender;
@end
@implementation PGToggleButton
@synthesize on = _on;
@synthesize offStateImage = _offStateImage;
@synthesize onStateImage = _onStateImage;
-(void)awakeFromNib
{
[super awakeFromNib];
self.offStateImage = [self imageForState:UIControlStateNormal];
self.onStateImage = [self imageForState:UIControlStateHighlighted];
[self addTarget:self
action:@selector(touchedUpInside:)
forControlEvents:UIControlEventTouchUpInside];
}
-(void)touchedUpInside:(UIButton*) sender
{ [self toggle]; }
-(void)toggle
{ self.on = toggle(_on); }
-(void)setOn:(BOOL) on
{
_on = on;
if (on)
[self setImage:self.onStateImage forState:(UIControlStateNormal)];
else
[self setImage:self.offStateImage forState:(UIControlStateNormal)];
}
@end
精彩评论