saikamesh
saikamesh

Reputation: 4629

Checkbox in iOS application

I need to add checkbox controls to my form. I know that there is no such control in iOS SDK. How could I do this?

Upvotes: 36

Views: 72056

Answers (12)

Kaunteya
Kaunteya

Reputation: 3090

A simple UIButton subclass using SF symbols does the trick

class CheckBoxButton: UIButton {
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }

    func setup() {
        setImage(UIImage(systemName: "square.fill"), for: .normal)
        setImage(UIImage(systemName: "checkmark.square.fill"), for: .selected)
    }
}

Storyboard

If you are using storyboard, ensure button type is set to custom as seen in the image below

button type custom


Usage

All you have to do is toggle the isSelected variable in action/selector method

@objc func toggle(_ sender: UIButton) {
    sender.isSelected.toggle()
}


Demo

checkbox demo

Upvotes: 0

Cheok Yan Cheng
Cheok Yan Cheng

Reputation: 42720

A simple UIButton subclass will able to behave like checkbox found in Android.

import UIKit

class CheckedUIButton: UIButton {
    var checked: Bool = false {
        didSet {
            if checked {
                setImage(UIImage(systemName: "checkmark.circle"), for: .normal)
            } else {
                setImage(UIImage(systemName: "circle"), for: .normal)
            }
        }
    }
    
    //initWithFrame to init view from code
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        commonInit()
    }
     
    //initWithCode to init view from xib or storyboard
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        commonInit()
    }
    
    private func commonInit() {
        addTarget(self, action: #selector(self.checkedTapped), for: .touchUpInside)
    }

    @objc
    private func checkedTapped() {
        self.checked.toggle()
    }
}

Output

enter image description here

(Unchecked state)


enter image description here

(Checked state)

Upvotes: 1

S1LENT WARRIOR
S1LENT WARRIOR

Reputation: 12214

Extending to Adrean's idea, i've achieved this using a very simple approach.
My idea is to change button (lets say checkBtn) text depending upon its state, and then change button's state in its IBAction.
Below is the code how i did this:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [checkBtn setTitle:@"\u2610" forState:UIControlStateNormal];    // uncheck the button in normal state
    [checkBtn setTitle:@"\u2611" forState:UIControlStateSelected];  // check the button in selected state
}

- (IBAction)checkButtonTapped:(UIButton*)sender {
    sender.selected = !sender.selected;    // toggle button's selected state  

    if (sender.state == UIControlStateSelected) {    
        // do something when button is checked 
    } else {
        // do something when button is unchecked
    }
}

Upvotes: 9

hasan
hasan

Reputation: 24185

Subclass UIButton, drop a button to view controller, select it and change class name to CheckBox in the identity inspector.

#import "CheckBox.h"

@implementation CheckBox

#define checked_icon @"checked_box_icon.png"
#define empty_icon @"empty_box_icon.png"

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self)
    {
        [self setImage:[UIImage imageNamed:empty_icon] forState:UIControlStateNormal];
        [self addTarget:self action:@selector(didTouchButton) forControlEvents:UIControlEventTouchUpInside];
    }
    return self;
}

- (void)didTouchButton {
    selected = !selected;
    if (selected)
        [self setImage:[UIImage imageNamed:checked_icon] forState:UIControlStateNormal];
    else
        [self setImage:[UIImage imageNamed:empty_icon] forState:UIControlStateNormal];
}

@end

Upvotes: 1

slobodans
slobodans

Reputation: 859

Here is my version of checkbox for iphone.

It is single class which extends UIButton. It is simple so i will paste it here.

CheckBoxButton.h file content

#import <UIKit/UIKit.h>

@interface CheckBoxButton : UIButton

@property(nonatomic,assign)IBInspectable BOOL isChecked;

@end

CheckBoxButton.m file content

#import "CheckBoxButton.h"

@interface CheckBoxButton()

@property(nonatomic,strong)IBInspectable UIImage* checkedStateImage;
@property(nonatomic,strong)IBInspectable UIImage* uncheckedStateImage;

@end

@implementation CheckBoxButton

-(id)init
{
    self = [super init];

    if(self)
    {
        [self addTarget:self action:@selector(switchState) forControlEvents:UIControlEventTouchUpInside];
    }

    return self;
}

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    if(self)
    {
        [self addTarget:self action:@selector(switchState) forControlEvents:UIControlEventTouchUpInside];
    }

    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];

    if(self)
    {
        [self addTarget:self action:@selector(switchState) forControlEvents:UIControlEventTouchUpInside];
    }

    return self;
}

-(void)setIsChecked:(BOOL)isChecked
{
    _isChecked = isChecked;

    if(isChecked)
    {
        [self setImage:self.checkedStateImage forState:UIControlStateNormal];
    }
    else
    {
        [self setImage:self.uncheckedStateImage forState:UIControlStateNormal];
    }
}

-(void)switchState
{
    self.isChecked = !self.isChecked;
    [self sendActionsForControlEvents:UIControlEventValueChanged];
}

@end

You can set images for checked/unchecked as well as isChecked property in the attribute inspector of visual studio.

enter image description here

To add CheckBoxButton in storyboard or xib, simple add UIButton and set custom class like on next image.

enter image description here

Button will send UIControlEventValueChanged event, every time when isChecked state is changed.

Upvotes: 6

mTouch
mTouch

Reputation: 11

I made it with a UITextField to avoid drawing anything strange but I liked putting inside as text the tick unicode (Unicode Character 'CHECK MARK' (U+2713)) for the NSString: @"\u2713".

This way, in my .h file (implementing the protocol for the UITextField 'UITextFieldDelegate'):

UITextField * myCheckBox;

In my viewDidLoad or the function to prepare the UI:

...
myCheckBox = [[UITextField alloc] initWithFrame:aFrame];
myCheckBox.borderStyle = UITextBorderStyleRoundedRect; // System look like
myCheckBox.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
myCheckBox.textAlignment = NSTextAlignmentLeft;
myCheckBox.delegate = self;
myCheckBox.text = @" -"; // Initial text of the checkbox... editable!
...

Then, add an event selector for reating in the touch event and calling 'responseSelected' event:

...
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(checkboxSelected)];
[myCheckBox addGestureRecognizer:tapGesture];
...

Finally respond to that selector

-(void) checkboxSelected
{
    if ([self isChecked])
    {
        // Uncheck the selection
        myCheckBox.text = @" -";
    }else{
       //Check the selection
       myCheckBox.text = @"\u2713";
    }
}

The function 'isChecked' only checks if the text is the @"\u2713" check mark. To prevent showing the keyboard when the text field is selected use the event of the UITextField 'textFieldShouldBeginEditing' and add the event selector to manage the selection:

-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
    // Question selected form the checkbox
    [self checkboxSelected];

    // Hide both keyboard and blinking cursor.
    return NO;
}

Upvotes: 1

Dilip Manek
Dilip Manek

Reputation: 9143

in .h file

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    BOOL isChecked;
    UIImageView * checkBoxIV;
}
@end

And .m file

- (void)viewDidLoad
{
    [super viewDidLoad];
    isChecked = NO;

    //change this property according to your need
    checkBoxIV = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 15, 15)]; 
    checkBoxIV.image =[UIImage imageNamed:@"checkbox_unchecked.png"]; 

    checkBoxIV.userInteractionEnabled = YES;
    UITapGestureRecognizer *checkBoxIVTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handlecheckBoxIVTapGestureTap:)];
    checkBoxIVTapGesture.numberOfTapsRequired = 1;
    [checkBoxIV addGestureRecognizer:checkBoxIVTapGesture];
}

- (void)handlecheckBoxIVTapGestureTap:(UITapGestureRecognizer *)recognizer {
    if (isChecked) {
        isChecked = NO;
        checkBoxIV.image =[UIImage imageNamed:@"checkbox_unchecked.png"];
    }else{
        isChecked = YES;
        checkBoxIV.image =[UIImage imageNamed:@"checkbox_checked.png"];   
    }
}

This will do the trick...

Upvotes: 1

Adrian
Adrian

Reputation: 532

this has been driving me mad too and I found a different solution that works well for me and avoids having to use images.

  1. Add a new label object to Interface Builder.
  2. Create an IBOutlet property in Xcode and connect it up to it. In the code below I've called it 'fullyPaid' as I want to know if someone has fully paid a sum of money.
  3. Add the 2 functions below. The 'touchesBegan' function checks if you touched somewhere inside the 'fullyPaid' label object and if so, it calls the 'togglePaidStatus' function. The 'togglePaidStatus' function sets up two strings which have the unicode characters representing an empty box (\u2610) and a checked box (\u2611) respectively. Then it compares what's currently in the 'fullyPaid' object and toggles it with the other string.

You might want to call the togglePaidStatus function in the viewDidLoad function to set it to an empty string initially.

Obviously you can add extra checks to prevent users toggling the checkbox if the label is not enabled, but that's not shown below.

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];   
    if (CGRectContainsPoint([fullyPaid frame], [touch locationInView:self.view]))
    {
        [self togglePaidStatus];
    }
}
-(void) togglePaidStatus
{
    NSString *untickedBoxStr = [[NSString alloc] initWithString:@"\u2610"];
    NSString *tickedBoxStr = [[NSString alloc] initWithString:@"\u2611"];   

    if ([fullyPaid.text isEqualToString:tickedBoxStr])
    {
        fullyPaid.text = untickedBoxStr;
    }
    else
    {
        fullyPaid.text = tickedBoxStr;
    }

    [tickedBoxStr release];
    [untickedBoxStr release];
}

Upvotes: 32

hiepnd
hiepnd

Reputation: 811

I like the idea of Adrian to use the characters rather than images. But I don't like the box, it need only the checkmark itself (@"\u2713"). I draw a box (a rounded box) programmatically and place an UILabel contains the checkmark inside it. This way of implementation makes it easy to use the custom view in any application without care about any dependent resource. You can also customize the color of the checkmark, the rounded box and the background with ease. Here's the complete code:

#import <UIKit/UIKit.h>

@class CheckBoxView;

@protocol CheckBoxViewDelegate
- (void) checkBoxValueChanged:(CheckBoxView *) cview;
@end

@interface CheckBoxView : UIView {
    UILabel *checkMark;
    bool isOn;
    UIColor *color;
    NSObject<CheckBoxViewDelegate> *delegate;
}
@property(readonly) bool isOn;
@property(assign) NSObject<CheckBoxViewDelegate> *delegate;

- (void) drawRoundedRect:(CGRect) rect inContext:(CGContextRef) context;
@end



#import "CheckBoxView.h"

#define SIZE 30.0
#define STROKE_WIDTH 2.0
#define ALPHA .6
#define RADIUS 5.0

@implementation CheckBoxView
@synthesize isOn, delegate;

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, SIZE, SIZE)])) {
        // Initialization code
    }
    //UIColor *color = [UIColor blackColor];
    color = [[UIColor alloc] initWithWhite:.0 alpha:ALPHA];

    self.backgroundColor = [UIColor clearColor];
    checkMark = [[UILabel alloc] initWithFrame:CGRectMake(STROKE_WIDTH, STROKE_WIDTH, SIZE - 2 * STROKE_WIDTH, SIZE - 2*STROKE_WIDTH)];
    checkMark.font = [UIFont systemFontOfSize:25.];
    checkMark.text = @"\u2713";
    checkMark.backgroundColor = [UIColor clearColor];
    checkMark.textAlignment = UITextAlignmentCenter;
    //checkMark.textColor = [UIColor redColor];
    [self addSubview:checkMark];
    [checkMark setHidden:TRUE];
    isOn = FALSE;
    return self;
}


// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
    CGRect _rect = CGRectMake(STROKE_WIDTH, STROKE_WIDTH, SIZE - 2 * STROKE_WIDTH, SIZE - 2*STROKE_WIDTH);
    [self drawRoundedRect:_rect inContext:UIGraphicsGetCurrentContext()];
    [checkMark setHidden:!isOn];
}


- (void)dealloc {
    [checkMark release];
    [color release];
    [super dealloc];
}

- (void) drawRoundedRect:(CGRect) rect inContext:(CGContextRef) context{
    CGContextBeginPath(context);
    CGContextSetLineWidth(context, STROKE_WIDTH);
    CGContextSetStrokeColorWithColor(context, [color CGColor]);
    CGContextMoveToPoint(context, CGRectGetMinX(rect) + RADIUS, CGRectGetMinY(rect));
    CGContextAddArc(context, CGRectGetMaxX(rect) - RADIUS, CGRectGetMinY(rect) + RADIUS, RADIUS, 3 * M_PI / 2, 0, 0);
    CGContextAddArc(context, CGRectGetMaxX(rect) - RADIUS, CGRectGetMaxY(rect) - RADIUS, RADIUS, 0, M_PI / 2, 0);
    CGContextAddArc(context, CGRectGetMinX(rect) + RADIUS, CGRectGetMaxY(rect) - RADIUS, RADIUS, M_PI / 2, M_PI, 0);
    CGContextAddArc(context, CGRectGetMinX(rect) + RADIUS, CGRectGetMinY(rect) + RADIUS, RADIUS, M_PI, 3 * M_PI / 2, 0);
    CGContextClosePath(context);
    CGContextStrokePath(context);
}

#pragma mark Touch
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    UITouch *touch = [touches anyObject];
    CGPoint loc = [touch locationInView:self];
    if(CGRectContainsPoint(self.bounds, loc)){
        isOn = !isOn;
        //[self setNeedsDisplay];
        [checkMark setHidden:!isOn];
        if([delegate respondsToSelector:@selector(checkBoxValueChanged:)]){
            [delegate checkBoxValueChanged:self];
        }
    }
}

Upvotes: 1

cannyboy
cannyboy

Reputation: 24426

I wanted to do this programmatically, and also solve the problem that the hit area was really too small. This is adapted from various sources, including Mike and Mike's commenter Agha.

In your header

@interface YourViewController : UIViewController {
    BOOL checkboxSelected;
    UIButton *checkboxButton;
}

@property BOOL checkboxSelected;;
@property (nonatomic, retain) UIButton *checkboxButton;

-(void)toggleButton:(id)sender;

And in your implementation

// put this in your viewDidLoad method. if you put it somewhere else, you'll probably have to change the self.view to something else
// create the checkbox. the width and height are larger than actual image, because we are creating the hit area which also covers the label
UIButton* checkBox = [[UIButton alloc] initWithFrame:CGRectMake(100, 60,120, 44)];  
[checkBox setImage:[UIImage imageNamed:@"checkbox.png"] forState:UIControlStateNormal];
// uncomment below to see the hit area
// [checkBox setBackgroundColor:[UIColor redColor]];
[checkBox addTarget:self action:@selector(toggleButton:) forControlEvents: UIControlEventTouchUpInside];
// make the button's image flush left, and then push the image 20px left
[checkBox setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[checkBox setImageEdgeInsets:UIEdgeInsetsMake(0.0, 20.0, 0.0, 0.0)];
[self.view addSubview:checkBox];

// add checkbox text text
UILabel *checkBoxLabel = [[UILabel alloc] initWithFrame:CGRectMake(140, 74,200, 16)];
[checkBoxLabel setFont:[UIFont boldSystemFontOfSize:14]];
[checkBoxLabel setTextColor:[UIColor whiteColor]];
[checkBoxLabel setBackgroundColor:[UIColor clearColor]];
[checkBoxLabel setText:@"Checkbox"];
[self.view addSubview:checkBox];

// release the buttons
[checkBox release];
[checkBoxLabel release];

And put this method in too:

- (void)toggleButton: (id) sender
{
    checkboxSelected = !checkboxSelected;
    UIButton* check = (UIButton*) sender;
    if (checkboxSelected == NO)
        [check setImage:[UIImage imageNamed:@"checkbox.png"] forState:UIControlStateNormal];
    else
        [check setImage:[UIImage imageNamed:@"checkbox-checked.png"] forState:UIControlStateNormal];

}

Upvotes: 6

Becca Royal-Gordon
Becca Royal-Gordon

Reputation: 17861

If you're showing a group of options and the user can select one of them, use a tableview with a checkmark accessory and a different text color on the selected row.

If you have a single option, your best bet is to use a switch. If you can't or don't want to, use a button, setting the normal image to an empty box and the selected image to a checked box. You'll have to make those two images yourself or find stock graphics to use for them.

Upvotes: 14

Eric Petroelje
Eric Petroelje

Reputation: 60508

Generally, you would use the UISwitch for checkbox-like functionality.

You could roll your own though by using an image control with two images (checked/unchecked) and switching the images when they touch the control/

Upvotes: 25

Related Questions