Please disable AdBlock. CAN is an ad-supported site that takes hundreds of hours and thousands of dollars to sustain. Read More.
HOLO is a biannual magazine about emerging trajectories in art, science, and technology brought to you by the people behind CAN. Learn more!

Integrating native UIKit to your existing OpenFrameworks iOS project

uikit

You have been working on an iOS project in OpenFrameworks and you got to a point where the need of adding native UIKit components is essential, well I will try my best to show you how to do just that. Here is what we’ll do:

• Create a View Controller from scratch
• Implement this View to your current OF project
• Add a couple of UIKit components to adjust parameters on our OF project

You don’t need to be an expert in Objective-C and/or iOS development but basic knowledge will help understand the process better.

Requirements

OF v0073
XCode 4.5.x

Support

If you are having problems following the tutorial or need a more in deep explanation please leave a comment below or contact me on:
• Twitter @nardove
• Email root[at]nardove.com

Setting up

To start the tutorial, lets create a new OF project for iOS, that will draw a solid circle in the middle of the screen, here is how your code should looks like:

testApp.h

#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"

class testApp : public ofxiPhoneApp{

public:
	void setup();
	void update();
	void draw();
	void touchDoubleTap(ofTouchEventArgs & touch);

	float radius;
	bool hasFill;
};

testApp.mm

#include "testApp.h"

void testApp::setup() {	
	ofBackground( ofColor::red );

	radius = 100;
	hasFill = true;
}

void testApp::update() {

}

void testApp::draw() {
	if ( hasFill ) {
		ofFill();
	}
	else {
		ofNoFill();
	}
	ofSetColor( ofColor::white );
	ofCircle( ofGetWidth() / 2, ofGetHeight() / 2, radius );
}

void testApp::touchDoubleTap(ofTouchEventArgs & touch) {

}

First Steps

We will create 3 new files in the src folder, select src and Right+Click on the menu select New File and create the following 3 files:
• MyGuiView.h
• MyGuiView.mm
• MyGuiView.xib

On the New File window under iOS select C and C++

creating-files-1

Name your file, and change the extension of the newly created .cpp file to .mm, this will allow to mix Objective-C with C++ code in the same file, then New File again select User Interface and select View, click Next, on Device Family select iPhone, click Next and finally name your xib file and click on Create.

Note: make sure that all files share the same name it is very important.

creating-files-2

You should see something like the image below in your Project Navigator:

files-list

Before we setup our xib file lets add the necessary code to its class.

Open MyGuiView.h and add the following:

#import <UIKit/UIKit.h>

@interface MyGuiView : UIViewController
@end

Then open MyGuiView.mm and add:

#include "MyGuiView.h"
#include "ofxiPhoneExtras.h"
#include "testApp.h"

@implementation MyGuiView

testApp *myApp;

-(void)viewDidLoad {
	myApp = (testApp*)ofGetAppPtr();
}
@end

After this is done we can setup our xib file MyGuiView.xib double click on it, Xcode will automatically change its view to deal with xib files. You will notice a couple of icons in the middle of the window.

filesowner-view

First click on File’s Owner icon and on the Identity Inspector change its Class to MyGuiView.

filesowner-set-class

Then on the Connections Inspector connect the outlet view to the View icon.

filesowner-set-view-outlet

You can now set the view properties specific to your device, I recommend to change the view background to a different colour from you testApp and make it slightly transparent, that way we can see the changes to our app as we change parameters from our view.

view-settings-attributes

Lets set our OF project, open testApp.mm and add the following code:

#include "MyGuiView.h"
MyGuiView *gui;

void testApp::setup() {	
	...
	gui = [[MyGuiView alloc] initWithNibName:@"MyGuiView" bundle:nil];
	[ofxiPhoneGetGLView() addSubview:gui.view];
}
...
void testApp::touchDoubleTap(ofTouchEventArgs & touch) {
	// toggle gui view visibility 
	gui.view.hidden = !gui.view.hidden;
}

If you Compile and Run you should see the new UIView on top of testApp, and when a double tap is detected the UIView should show and hide accordingly.

Setting up our GUI

Lets go back to MyGuiView.h and add the following code mark in bold letters:

#import <UIKit/UIKit.h>

@interface MyGuiView : UIViewController

@property(retain, nonatomic) IBOutlet UISlider *radiusSlider;
@property(retain, nonatomic) IBOutlet UISwitch *fillSwitch;

@end

We just created our outlets to tell XCode that those properties we’re going to want to connect to an object(s) in our xib file.

Open MyGuiView.mm and add the following:

#include "MyGuiView.h"
#include "ofxiPhoneExtras.h"
#include "testApp.h"

@implementation MyGuiView

testApp *myApp;

-(void)viewDidLoad {
	myApp = (testApp*)ofGetAppPtr();
}

-(IBAction)radiusSliderHandler:(id)sender {
	UISlider *sliderObj = sender;
	myApp->radius = [sliderObj value];
}

-(IBAction)fillSwitchHandler:(id)sender {
	UISwitch *switchObj = sender;
	myApp->hasFill = [switchObj isOn];
}

@end

These are the methods that can be triggered by a control in a xib file.

Now we’ll add the necessary components to our UIView, open up MyGuiView.xib, if the Utilities panel is not already open select View > Utilities > Show Utilities. First select a Label object from the Object Library and drag it to the view, preferably to the top left corner, double click on it to change its text to “Circle Radius”.

utilities-object-library

Underneath the Circle radius label add another Label, change its text to “Render fill”, then add a Slider next to the Circle radius label adjust its size to the edge of the screen until you see the blue margin line, after that add a Switch next to Render fill label, place it near until you see the margin blue line. You should have something like the image below:

uiview-with-components

Now click on the slider component again and open the Attributes Inspector to change its minimum, maximum and current starting values, it should look something like this:

slider-attributes-inspector

We are almost done, click on the File’s Owner icon and open up the Connection Inspector

filesowner-connections-inspector

All we need to do here is make a couple of connections, we’ll connect our outlets to our components, on the Outlets panel click on the circle on the right of radiusSlider and drag it to the slider next to the Circle radius label like shown in the following image:

outlet-connection-slider

Do the same for the fillSwitch outlet like this:

outlet-connection-switch

The last step is to tell the components what to do when the user interact with them (connect action methods), to make this happen we most connect the action method to the corresponding component, on the Received Actions panel click and drag the circle next to radiusSliderHandler to the slider component, a drop down menu will appear from there select Value Changed, what this means is that every time the slider change its value the attached method will be called updating the corresponding values.

outlet-action-connection-slider

And we do the same for the switch component, click and drag the circle next to fillSwitchHandler to the switch component, from the drop down menu select Value Changed.

outlet-action-connection-switch

And this is it! Run the project and you should be able to changes the circle appearance using the controls we just created.

I hope this tutorial has help you to understand the process of setting up UIKit components to your existing OF project, and give you a starting point to learn how to add other types of components.

You can find a entire project here (download NativeUIKitExample.zip)

    • McFlyyy

      Isn’t it better to learn how to code instead of learning how to drag & drop stuff ? #xibHater

    • RonH

      Many thanks – this is hugely helpful. I’d been struggling with how to integrate Obj C and C++ in my Open Frameworks iOS app, but your tutorial has enabled me to move forward.

      McFlyyy: why does one have to be better than another? What’s ‘best’ for me is using whatever it takes to get the job done. Besides, what’s being presented here is not just dragging and dropping, but also coding. In the world of sound (my own specialty), two of the most powerful programming environments available – Max/MSP and Reaktor – combine a graphic approach with coding.

    • Paul Mans

      Thanks for posting this. I was wondering how to do this and really appreciate the clear explanation