In this blog we’ll examine how to create a view object in Interface Builder that is backed by a UIView. We’ll control the view’s color and alpha channel properties by using sliders. The app will demonstrate how to force a view to refresh after a property of it has been changed. So let’s see how it works!
Start Xcode, select “Create a new Xcode project,” choose the Single View Application template, and click Next. Name the project ColorView, and select options as shown here:
Click Next, choose a location to save the project, and click Create.
First, we’ll need to add a UIView object to our app. Create the object by navigating to File | New File… and choosing the Objective – C Class template. Click Next. In the “Subclass of” dropdown choose UIView. Name The class “Circle” and click Next. In the next window, click Create to save the class in the project location.
Open Circle.h and make these changes:
@interface Circle : UIView
@property (nonatomic, assign) CGFloat redValue;
@property (nonatomic, assign) CGFloat greenValue;
@property (nonatomic, assign) CGFloat blueValue;
@property (nonatomic, assign) CGFloat alpha;
@end
We’ve added properties to represent the aspects of the view we will control from the interface. Next, open Circle.m to make these changes:
@implementation Circle
@synthesize redValue, greenValue, blueValue, alpha;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, self.redValue,
self.greenValue,
self.blueValue,
self.alpha);
CGContextFillEllipseInRect(context, rect);
CGContextFillPath(context);
}
@end
Setting the background color to clear ensures that no matter what color the main view is, only a circle will be displayed. This circle is drawn in drawRect:.
Now open ViewController.h and add these properties and methods:
#import "Circle.h"
@interface ViewController : UIViewController
@property (nonatomic, strong) IBOutlet Circle *circle;
- (IBAction)redChanged:(UISlider *)sender;
- (IBAction)greenChanged:(UISlider *)sender;
- (IBAction)blueChanged:(UISlider *)sender;
- (IBAction)alphaChanged:(UISlider *)sender;
@end
Our new view (circle) is defined as an outlet. We’ll wire this up in Interface Builder in a moment. Four actions are also defined to interact with four UISlider controls.
Open ViewController.m and make the following changes:
@interface ViewController ()
@end
@implementation ViewController
@synthesize circle;
- (Circle *)circle
{
if (!circle) {
circle = [[Circle alloc] init];
}
return circle;
}
- (IBAction)redChanged:(UISlider *)sender
{
self.circle.redValue = sender.value;
[self.circle setNeedsDisplay];
}
- (IBAction)greenChanged:(UISlider *)sender
{
self.circle.greenValue = sender.value;
[self.circle setNeedsDisplay];
}
- (IBAction)blueChanged:(UISlider *)sender
{
self.circle.blueValue = sender.value;
[self.circle setNeedsDisplay];
}
- (IBAction)alphaChanged:(UISlider *)sender
{
self.circle.alpha = sender.value;
[self.circle setNeedsDisplay];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.circle.redValue =
self.circle.greenValue =
self.circle.blueValue = (CGFloat)0;
self.circle.alpha = (CGFloat)1;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
After synthesizing circle, we lazily instantiate it by overriding its getter. Next come the four action methods. In each case, we set the property of circle that we are interested in to the current value of the slider, then force the circle to be redrawn by sending it the message setNeedsDisplay.
In viewDidLoad, the initial color values of the circle are all set to 0, and the alpha is set to 1. These values must be cast to CGFloats, because the corresponding properties of Circle are declared to be of that type.
Now we can wire up the interface objects. Open Interface Builder by clicking on ViewController.xib. Create this user interface:
The large square object at the top is a UIView. In the Identity Inspector, change its Class to Circle as shown here:
Make sure the values of the sliders are set (from top to bottom) to 0, 0, 0, 1. Now wire up the property and the four methods as shown in the Files Owner property window here:
Note that the circle outlet cannot be wired to the UIView in Interface Builder until the view’s class is changed to Circle as described above.
Save all of your work, and run the app. Watch the color of the circle change as the sliders are moved. Enjoy!
As an exercise, comment out the calls to setNeedsDisplay in each of the action methods. What happens? Why?