Creating Controls In Code

Sometimes it is useful to be able to create and add controls to views in code, without using Interface Builder. In this blog post, we’ll learn how to add a button and a label to our view. Other controls will follow the same general pattern. The source code for this example is here: CodedControls

If you want to start from scratch, start up Xcode and make a new single view application. Open the ViewController.h file, and add a property for a UIButton as shown:

#import

@interface ViewController : UIViewController

@property (nonatomic, weak) UIButton *button;

@end

Now open ViewController.m. First, modify the viewDidLoad method:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self makeButton];
}

Don’t worry that the makeButton method is undefined, we’ll define it next. In fact, here it is now:

- (void)makeButton
{
    //make a new button and display it on the view.
    CGRect buttonFrame = CGRectMake(self.view.frame.size.width/2 - 150/2,
                                    30, 150, 50);
    self.button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    self.button.frame = buttonFrame;
    [self.button setTitle:@"Hello" forState:UIControlStateNormal];
    [self.button addTarget:self
                    action:@selector(buttonPressed)
          forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.button];
}

All UIControls are subclasses of UIView, and all views need a frame. Here, we set the button’s frame to be 150 points wide and 50 points tall, centered in the view, and 30 points from the top. Next, we actually instantiate the UIButton, and assign the instance to self.button. (We really don’t need a property for this, but I’ve made a property for clarity). We set the title on the button.

The next line sets the target and action for the touch up inside event on the button. The target in this case is self (this view controller), the action is a selector that we will define in a moment, and the control event is UIControlEventTouchUpInside. Other controls have other control events, but you will see all of them listed in the code completion tool tips when you begin typing UIControlEvent… for a specific control.

Finally, we add the button we’ve just made to the controller’s view as a subview. The button property was defined as weak (having an initial reference count of 0). When we assign it to the view controller’s view, the button gets a reference count of 1. Later, when the view is deleted, the button will be deleted as well.

The selector we set as the action method for the button is called buttonPressed. I guess we’d better define that method, too:

- (void)buttonPressed
{
    NSLog(@"Hello, button");
    if ([self.button.titleLabel.text isEqualToString:@"Hello"]) {
        [self.button setTitle:@"OK" forState:UIControlStateNormal];

        //Make a label, add it to the view:
        UILabel *label = [UILabel new];
        label.frame = CGRectMake(0, 100, 320, 22);
        [label setTextAlignment:NSTextAlignmentCenter];
        label.text = @"Hello, button";
        //set the label's tag so we can easily find it later:
        label.tag = 1;
        [self.view addSubview:label];
    } else {
        [self.button setTitle:@"Hello" forState:UIControlStateNormal];
        //find the label and remove it from the view.
        //because "label" was local to the above if block,
        //it is deleted from memory.
        for (UIView *view in self.view.subviews) {
            if (view.tag == 1) {
                [view removeFromSuperview];
            }
        }
    }
}

After logging out “Hello, button” to the console, we get the current text on the button. If the text is “Hello” we change it to “OK.” Then we create a new label. We set several properties on the label, including it’s tag value to make it easier to find later. The label is displayed by adding it to the controller’s view as a subview in the same way as the button was displayed. Note that “label” is local to the if clause: if the label had not been added to the subview, it would not be retained by any other object, and ARC would reclaim its memory. By making it a subview of the controller’s view, we’ve given it a retain count of one.

In the else clause, we set the text on the button back to “Hello.” Then we remove the label by finding it by inspecting the tag property on all subviews of the controller’s view. As soon as we call removeFromSuperview, the label’s retain count drops to 0, and ARC releases its memory the next time through the run loop.

Run the app. When the view is displayed, a new button is created. When the button is tapped, a new label is created on the view and the text on the button changes. Tapping the button again makes the label go away (it is actually removed from the view and deleted from memory). You can repeat this cycle as often as you want.

Try dynamically creating a slider, and setting the text on a dynamically created label depending on the slider’s value. Or maybe make an image view dynamically. . . Now that you know the basic principles, you can make virtually any user interface entirely in code!

Leave a Comment: