Radio buttons is a set of buttons out of which only one can be set at a time. For example: Selecting the time format out of 12-hr and 24-hr in a clock application.They are often required in iPhone UIs. Unfortunately, they are not included in the iPhone sdk. In this tutorial, we will learn how to create custom radio buttons.

Step 1: Create a window based application in Xcode and name it “MIRadioButtonGroup”.

Step 2: Create new “MIRadioButtonGroup.h” and “MIRadioButtonGroup.m” files which extend from UIView.
(Classes >> Add >> New File >> Objective C Class. Select UIView in the “subclass of” list.)

Step 3: Create a new group in the Classes folder and name it “MIRadioButtonGroup”. Drag the “MIRadioButtonGroup .h” and “MIRadioButtonGroup .m” files into the group.Now, add the images “radio-on.png” and “radio-off.png” to the group.

Step 4: Open the “MIRadioButtonGroup.h” file and make the following changes in it.

@interface MIRadioButtonGroup : UIView {
NSMutableArray *radioButtons;
}

@property (nonatomic,retain) NSMutableArray *radioButtons;

- (id)initWithFrame:(CGRect)frame andOptions:(NSArray *)options  
          andColumns:(int)columns;
-(IBAction) radioButtonClicked:(UIButton *) sender;
-(void) removeButtonAtIndex:(int)index;
-(void) setSelected:(int) index;
-(void)clearAll;
@end

Here, we have declared a mutable array “radioButtons” which will hold all the buttons that we add to the radio button group.

The methods declared are:
initWithFrame – It is a constructor used to initialize the group. It takes the frame for the entire group,an array holding the titles of the buttons and the number of columns in which the buttons are to be arranged as input parameters.

radioButtonClicked – This method is used to set the button which is clicked.

removeButtonAtIndex – This method is used to remove a radio button at a particular index from the group.

setSelected – This method is used to set the button at the specified index.

clearAll – This method clears all the buttons including the currently set button.

Step 5: Open the “MIRadioButtonGroup.m” file and put the following code in it.

#import "MIRadioButtonGroup.h"

@implementation MIRadioButtonGroup
@synthesize radioButtons;

- (id)initWithFrame:(CGRect)frame andOptions:(NSArray *)options  
      andColumns:(int)columns{

               NSMutableArray *arrTemp =[[NSMutableArray alloc]init];
               self.radioButtons =arrTemp;
               [arrTemp release];
              if (self = [super initWithFrame:frame]) {
                      // Initialization code
                      int framex =0;
                      framex= frame.size.width/columns;
                      int framey = 0;
                      framey =frame.size.height/([options count]/(columns));
                      int rem =[options count]%columns;
                      if(rem !=0){
                             framey =frame.size.height/(([options  count]  
                                            /columns)+1);
            } 
            int k = 0;
            for(int i=0;i<([options count]/columns);i++){
                 for(int j=0;j<columns;j++){

                          int x = framex*0.25;
                          int y = framey*0.25;
                          UIButton *btTemp = [[UIButton alloc] 
                           initWithFrame:CGRectMake(framex*j+x, framey*i+y, 
                           framex/2+x, framey/2+y)];
                           [btTemp addTarget:self action: 
                           @selector(radioButtonClicked:) 
                            forControlEvents:UIControlEventTouchUpInside];
                            btTemp.contentHorizontalAlignment =  
                             UIControlContentHorizontalAlignmentLeft;
                           [btTemp setImage:[UIImage imageNamed: 
                           @"radio-off.png"] forState:UIControlStateNormal];
                           [btTemp setTitleColor:[UIColor blackColor] 
                            forState:UIControlStateNormal];
                           btTemp.titleLabel.font =[UIFont systemFontOfSize:14.f];
                         [btTemp setTitle:[options objectAtIndex:k] 
                                 forState:UIControlStateNormal];
                         [self.radioButtons addObject:btTemp];
                         [self addSubview:btTemp];
                         [btTemp release];
                         k++;

               }
        }

        for(int j=0;j<rem;j++){

                int x = framex*0.25;
                int y = framey*0.25;
                UIButton *btTemp = [[UIButton   alloc] 
                   initWithFrame:CGRectMake(framex*j+x, 
                   framey* ([options count]/columns), 
                                                framex/2+x,framey/2+y)];
                [btTemp addTarget:self action:@selector(radioButtonClicked:)  
                   forControlEvents:UIControlEventTouchUpInside];
                btTemp.contentHorizontalAlignment =  
                     UIControlContentHorizontalAlignmentLeft;
               [btTemp setImage:[UIImage imageNamed:@"radio-off.png"]  
                                  forState:UIControlStateNormal];
               [btTemp setTitleColor:[UIColor blackColor]  
                                    forState:UIControlStateNormal];
               btTemp.titleLabel.font =[UIFont systemFontOfSize:14.f];
               [btTemp setTitle:[options objectAtIndex:k]  
                                        forState:UIControlStateNormal];
               [self.radioButtons addObject:btTemp];
               [self addSubview:btTemp];
               [btTemp release];
               k++;

        }

    }
       return self;
}

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

-(IBAction) radioButtonClicked:(UIButton *) sender{
           
           for(int i=0;i<[self.radioButtons count];i++){
                   [[self.radioButtons objectAtIndex:i] setImage:[UIImage    
                               imageNamed:@"radio-off.png"]  
                                    forState:UIControlStateNormal];
           }
           [sender setImage:[UIImage imageNamed:@"radio-on.png"]   
                                 forState:UIControlStateNormal];

}

-(void) removeButtonAtIndex:(int)index{
           [[self.radioButtons objectAtIndex:index] removeFromSuperview];
}

-(void) setSelected:(int) index{
        for(int i=0;i<[self.radioButtons count];i++){
             [[self.radioButtons objectAtIndex:i] setImage:[UIImage   
           imageNamed:@"radio-off.png"] forState:UIControlStateNormal];

         }
         [[self.radioButtons objectAtIndex:index] setImage:[UIImage  
          imageNamed:@"radio-on.png"] forState:UIControlStateNormal];

}

-(void)clearAll{
          for(int i=0;i<[self.radioButtons count];i++){
                     [[self.radioButtons objectAtIndex:i] setImage:[UIImage  
                                                 imageNamed:@"radio-off.png"] 
                                                 forState:UIControlStateNormal];
            }
}

@end

initWithFrame – In this method, we first divide the frame into n number of boxes with width framex and height framey, where n =([options count]/columns)*columns. Then we check to see if there is any remainder for ([options count]/columns). The reason for this will be explained later.
In the proceeding nested “for” loops, we set the frames of the buttons so that each button occupies 50% space of each of the n boxes. After that we link the button programmatically to the “radioButtonClicked” method. We set the alignment of the content(radio button image and title) to left. Then we set the image for the button, configure its font color and font size and set its title.

This code works fine when the number of buttons is perfectly divisible by columns, but when it is not, the remaining buttons are not printed.
Now, the remainder comes in picture. What we do is, if there is a non-zero remainder, we add 1 to the divisor in framey equation,so that there is space for an extra row in the frame. In the next “for” loop, we insert that extra row and hence, cover the missing buttons.

radioButtonClicked – Here, we first clear all the buttons in the “radioButtons” array by setting their images to “radio-off.png”. Then, we set only the sender button by setting its image to “radio-off”.

removeButtonAtIndex – In this method, we remove the button at the specified index with the “removeFromSuperview” method.

setSelected – This method is similar to the “radioButtonClicked” method. The difference is we set the button at the specified index in the “radioButtons” array.

clearAll – In this method, we clear all the radio buttons by setting the images of the buttons in “radioButton” to “radio-off.png”.

Step 6: Now that we have created the “MIRadioButtonGroup” files, put the following code in the “MIRadioButtonGroupAppDelegate.m” file so that we can test them.

#import "MIRadioButtonGroupAppDelegate.h"
#import "MIRadioButtonGroup.h"

@implementation MIRadioButtonGroupAppDelegate
@synthesize window;

- (void)applicationDidFinishLaunching:(UIApplication *)application {

         // Override point for customization after application launch
         NSArray *options =[[NSArray alloc] 
                        initWithObjects:@"1",@"2",@"3",@"4",@"5",@"6",nil];
         MIRadioButtonGroup *group =[[MIRadioButtonGroup alloc]
                                   initWithFrame:CGRectMake(0, 20, 320, 75)  
                                             andOptions:options andColumns:4];
          [options release];
          [window addSubview:group];
          //[group setSelected:1];
         //[group clearAll];
        //[group removeButtonAtIndex:2];
        [window makeKeyAndVisible];
}

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

@end

Step 7: Save, build and run the project. The output will be Output1. Now uncomment the commented lines one by one and observe the output. It will be Output 2, Output 3 and Output 1 respectively.

You can download the source code here.