How To Make A Simple Drawing App with UIKit

This is a blog post by iOS Tutorial Team member Abdul Azeem, software architect and co-founder at Datainvent Systems, a software development and IT services company. At some stage in all of our lives, we enjoyed drawing pictures, cartoons, and other stuff. For me it was using a pen and paper when I was growing […] By .

Leave a rating/review
Save for later
Share
You are currently viewing page 4 of 5 of this article. Click here to view the first page.

Finishing Touches – Settings Integration

There’s still one important piece missing here. Did you notice what it was?

The updated opacity and width values are still not being applied to the ViewController drawing canvas! That’s because you have not yet communicated the values specified in the Settings screen to the ViewController yet. This is a perfect job for a delegate protocol.

Open SettingsViewController.h file and add the following code just below the imports:

@protocol SettingsViewControllerDelegate <NSObject>
- (void)closeSettings:(id)sender;
@end 

Also add a delegate property to the code:

@property (nonatomic, weak) id<SettingsViewControllerDelegate> delegate;

And synthesize the property in SettingsViewController.m if you need to:

@synthesize delegate;

Previously the SettingsController dismissed itself. Now, it will need to delegate the responsibility to the ViewController that presented the modal view controller.

First, change the definition of the ViewController.h class and advertise that this protocol is supported:

#import "SettingsViewController.h"

@interface ViewController : UIViewController <SettingsViewControllerDelegate> {
 

Now in SettingsViewController.m, call the delegate when the close button is tapped:

- (IBAction)closeSettings:(id)sender {
    [self.delegate closeSettings:self];
}

Then open ViewController.m and implement prepareForSegue so to set itself as the delegate and pass the current brush and opacity settings through:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    
    SettingsViewController * settingsVC = (SettingsViewController *)segue.destinationViewController;
    settingsVC.delegate = self;
    settingsVC.brush = brush;
    settingsVC.opacity = opacity;
    
}

Finally, implement the closeSettings delegate function:

#pragma mark - SettingsViewControllerDelegate methods

- (void)closeSettings:(id)sender {
    
    brush = ((SettingsViewController*)sender).brush;
    opacity = ((SettingsViewController*)sender).opacity;
    [self dismissViewControllerAnimated:YES completion:nil];
}

Notice how you are now fetching the updated brush and opacity values from the values set in SettingsController.

Compile and run! At this stage, you will see the brush and opacity values are now updated after you change them in the settings Screen.

Finishing Touches — A Custom Color Selector

Currently, you have 10 color buttons on your Drawing Canvas screen. However, with the custom RGB color selector, the discriminating artists using your app will have the ability to control to pick any available color from the RGB range.

Note: The RGB color model is an additive color model in which red, green, and blue light are added together in various ways to reproduce a broad array of colors. In iOS, the degree of intensity of red, green or blue is expressed with a floating point value between 0.0 and 1.0.

Various degrees of resolution are used in various computers – many years ago 24-bit color (“True color”), so called because each of R, G and B could have values from 0 to 255 (8 bits per channel, 24 bits total) was very high end but now it is common.

In this app, you will implement a true color 24-bit picker with 3 sliders that can have value from 0-255 for each of R, G and B channels.

Note: The RGB color model is an additive color model in which red, green, and blue light are added together in various ways to reproduce a broad array of colors. In iOS, the degree of intensity of red, green or blue is expressed with a floating point value between 0.0 and 1.0.

Various degrees of resolution are used in various computers – many years ago 24-bit color (“True color”), so called because each of R, G and B could have values from 0 to 255 (8 bits per channel, 24 bits total) was very high end but now it is common.

In this app, you will implement a true color 24-bit picker with 3 sliders that can have value from 0-255 for each of R, G and B channels.

Start with the RGB Color Selector control. Open MainStoryboard.storyboard and drag three UISliders and a few labels onto the Settings screen as you can see below:

Settings Layout 2

Set the range of Sliders from 0-255. Drag IBOutlets to SettingsViewController.h for each of the sliders, naming them redControl, greenControl and blueControl. Drag to connect the Value Changed action for all three to sliderChanged just as you did for the brushControl and opacityControl sliders.

Also connect each of the right-side labels to outlets so you can show the current value of each, naming them redLabel, greenLabel and blueLabel.

Since you’ve provided a preview of the brush size and opacity, you might as well provide a preview of the new brush color! :] The brush preview will be shown in the selected RGB color – as well, the opacity preview will be shown in the RGB color. No need for an extra image; you’ll re-use what you already have!

Open SettingsViewController.h and add the following three properties to save the current RGB values.

@property CGFloat red;
@property CGFloat green;
@property CGFloat blue;

Also synthesize these in SettingsViewController.m if you need to:

@synthesize red;
@synthesize green;
@synthesize blue;

Now open SettingsViewController.m and make the following changes to the SliderChanged function:

- (IBAction)sliderChanged:(id)sender {
    
    UISlider * changedSlider = (UISlider*)sender;
    
    if(changedSlider == self.brushControl) {
        
        self.brush = self.brushControl.value;
        self.brushValueLabel.text = [NSString stringWithFormat:@"%.1f", self.brush];
        
    } else if(changedSlider == self.opacityControl) {
        
        self.opacity = self.opacityControl.value;
        self.opacityValueLabel.text = [NSString stringWithFormat:@"%.1f", self.opacity];
        
    } else if(changedSlider == self.redControl) {
        
        self.red = self.redControl.value/255.0;
        self.redLabel.text = [NSString stringWithFormat:@"Red: %d", (int)self.redControl.value];
        
    } else if(changedSlider == self.greenControl){
        
        self.green = self.greenControl.value/255.0;
        self.greenLabel.text = [NSString stringWithFormat:@"Green: %d", (int)self.greenControl.value];
    } else if (changedSlider == self.blueControl){
        
        self.blue = self.blueControl.value/255.0;
        self.blueLabel.text = [NSString stringWithFormat:@"Blue: %d", (int)self.blueControl.value];
        
    }
    
    UIGraphicsBeginImageContext(self.brushPreview.frame.size);
    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
    CGContextSetLineWidth(UIGraphicsGetCurrentContext(),self.brush);
    CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), self.red, self.green, self.blue, 1.0);
    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), 45, 45);
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), 45, 45);
    CGContextStrokePath(UIGraphicsGetCurrentContext());
    self.brushPreview.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    UIGraphicsBeginImageContext(self.opacityPreview.frame.size);
    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
    CGContextSetLineWidth(UIGraphicsGetCurrentContext(),self.brush);
    CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), self.red, self.green, self.blue, self.opacity);
    CGContextMoveToPoint(UIGraphicsGetCurrentContext(),45, 45);
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(),45, 45);
    CGContextStrokePath(UIGraphicsGetCurrentContext());
    self.opacityPreview.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
}

In above code, notice how the variable values are updated as the sliders are being updated.

To ensure the correct values are displayed for color when settings opens, change prepareForSegue in ViewController.m to:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    
    SettingsViewController * settingsVC = (SettingsViewController *)segue.destinationViewController;
    settingsVC.delegate = self;
    settingsVC.brush = brush;
    settingsVC.opacity = opacity;
    settingsVC.red = red;
    settingsVC.green = green;
    settingsVC.blue = blue;
    
}

Now that SettingsViewController has the values to display, update viewWillAppear in SettingsViewController.m to:

- (void)viewWillAppear:(BOOL)animated {
    
    // ensure the values displayed are the current values
            
    int redIntValue = self.red * 255.0;
    self.redControl.value = redIntValue;
    [self sliderChanged:self.redControl];
    
    int greenIntValue = self.green * 255.0;
    self.greenControl.value = greenIntValue;
    [self sliderChanged:self.greenControl];
    
    int blueIntValue = self.blue * 255.0;
    self.blueControl.value = blueIntValue;
    [self sliderChanged:self.blueControl];
        
    self.brushControl.value = self.brush;
    [self sliderChanged:self.brushControl];
    
    self.opacityControl.value = self.opacity;
    [self sliderChanged:self.opacityControl];
    
}

Finally open ViewController.m and make the following changes to the closeSettings method:

#pragma mark - SettingsViewControllerDelegate methods

- (void)closeSettings:(id)sender {
    
    brush = ((SettingsViewController*)sender).brush;
    opacity = ((SettingsViewController*)sender).opacity;
    red = ((SettingsViewController*)sender).red;
    green = ((SettingsViewController*)sender).green;
    blue = ((SettingsViewController*)sender).blue;
    [self dismissViewControllerAnimated:YES completion:nil];
}

In the above code, as the SettingsViewController closes, the updated RGB values are being fetched as well.

All right — time for another compile and run stage! Put the Color Picker through its paces. The selected RGB color, which is displayed in RGBPreview, is now the default brush stroke color on the drawing canvas!

Settings screen improved

But what good is all of these wonderful works of art if you can’t share them with the world? Since you can’t stick the pictures up on your refrigerator, you’ll tweet them in the next step of this tutorial! :]