Apr 16

Many of the built-in applications on the iPhone have this nice blue pattern background.

iPhone Standard Screen Background Color

It’s easy to get the same effect in your applications. Just set the background to the built-in color called groupTableViewBackgroundColor. (Note that the documentation erroneously refers to this color as groupTableBackgroundColor.)

UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
view.backgroundColor = [UIColor groupTableViewBackgroundColor];

written by Nick Dalton \\ tags: ,

Apr 09

Say you want each customer to accept your Terms of Service, or some other legalese, before they can use your iPhone application.

Display the screen upon startup

The standard AppDelegate code generated by Xcode creates and displays your first application screen. Here’s a way that you can use the hidden property of UIView to display your new screen first without disrupting the flow of the rest of the application.

// Create window
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
[window setBackgroundColor:[UIColor whiteColor]];

// Set up main view navigation controller
MainMenuViewController *navController = [[MainMenuViewController alloc] init];

// Create a navigation controller using the new controller
navigationController = [[UINavigationController alloc] initWithRootViewController:navController];
navigationController.navigationBarStyle = UIBarStyleDefault;

[navController release];

// Create Terms of Service screen
tosController = [[TermsOfServiceViewController alloc] init];
[window addSubview:[tosController view]];
navigationController.view.hidden = YES;

// Add the navigation controller's view to the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];

Most of this is boilerplate code, more or less generated by Xcode. What’s new starts at line 14. Instantiate the new TermsOfServiceViewController and add it to the view. Standard stuff. The important line is #17, which hides the navigationController.

Dismiss the new screen

Now that the Terms of Service screen is displayed and the Main Menu is hidden we need a way to dismiss the ToS screen and return to the normal application flow.

In your AppDelegate class create a new method:

- (void)termsOfServiceAccepted
{
	tosController.view.hidden = YES;
	navigationController.view.hidden = NO;
}

In the TermsOfServiceController you would have a button that the user has to tap:

UIButton *acceptButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
acceptButton.frame = CGRectMake(kLeftMargin,
						applicationFrame.size.height - kBottomMargin - kButtonHeight,
						applicationFrame.size.width - kLeftMargin - kRightMargin,
						kButtonHeight);
[acceptButton setTitle:NSLocalizedString(@"ButtonAcceptTermsOfService", @"") forStates:UIControlStateNormal];
[acceptButton addTarget:self action:@selector(termsOfServiceAccepted:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:acceptButton];

When the button is tapped, the selector is called which in turn calls the above method in the AppDelegate.

- (void)termsOfServiceAccepted:(id)sender
{
	id applicationDelegate = [[UIApplication sharedApplication] delegate];
	[applicationDelegate termsOfServiceAccepted];
}

Only show the screen once

With this code the ToS screen is displayed every time the application is started. That will quickly get annoying. So let’s add some code to only show it once by using a boolean stored in NSUserDefaults.

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if (![userDefaults boolForKey:TERMS_OF_USE_ACCEPTED]) {
	tosController = [[TermsOfServiceViewController alloc] init];
	[window addSubview:[tosController view]];
	navigationController.view.hidden = YES;
}

And in the termsOfServiceAccepted method set the boolean in NSUserDefaults.

- (void)termsOfServiceAccepted
{
	tosController.view.hidden = YES;
	navigationController.view.hidden = NO;

	// Store acceptance in UserDefaults
	NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
	[userDefaults setBool:YES forKey:TERMS_OF_USE_ACCEPTED];
}

Now the ToS screen is only shown until the user taps the accept button. Your customers will be happy, as will your lawyers.

written by Nick Dalton \\ tags: , ,

Apr 03

A UIWebView is great for displaying rich text; you just format your text as HTML. But how do you display images in a UIWebView?

Since the iPhone is almost always connected you could just use a regular image tag referencing an image on a server somewhere:

<img src="http://example.com/img/foo.png" />

But that is less than optimal. What you really want to do is reference an image on the iPhone. One way to do this is to embed the image in the HTML using the data: URI scheme. Here’s an example:

<img src="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP
C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA
AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J
REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq
ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0
vr4MkhoXe0rZigAAAABJRU5ErkJggg==" alt="Red dot" />

Here’s a great tool for converting any small image to the base64 encoding required by data:image:
www.abluestar.com/utilities/encode_base64/index.php

Adding images this way will allow you to create great looking, self-contained help files and about us pages for your iPhone applications.

written by Nick Dalton \\ tags: , ,

Mar 31

Beta 2 of the iPhone SDK was launched last week and as advertised it now includes Interface Builder. Unfortunately somebody forgot to tell the documentation department at Apple about this. There is no documentation about Interface Builder related to the iPhone to be found anywhere. Zip. Nada. Nothing.

Of course there’s the general Introduction to Interface Builder User Guide, but does not deal with any of the specifics for building an iPhone interface.

Online forums are filled with messages from bewildered iPhone developers. Some brave bloggers have posted tutorials, which in many cases feel like putting a square peg into a round hole just to get the darn thing working.

I’ve found one tutorial that stands out from the crowd and actually makes sense from a Model-View-Controller (MVC) perspective. Check out Scott’s Reason #2: Interface Builder is buggy and has no documentation on his curiously named “I Hate the iPhone SDK” blog.

written by Nick Dalton \\ tags:

Mar 27

If you’re using a UIWebView to display rich text from a string of HTML (as I described yesterday) you can even include HTML links to external URLs.

However when the external web page is displayed it is done using the same scale as your local HTML page. Unless the two pages are about equal in size, the visual transition is less than pleasing.

You can use the scalesPageToFit property of UIWebView to fix this. See line 13:

- (void)loadView
{
  // Create a custom view hierarchy.
  CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
  UIView *view = [[UIView alloc] initWithFrame:appFrame];
  view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
  self.view = view;
  [view release];

  CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
  webView = [[UIWebView alloc] initWithFrame:webFrame];
  webView.backgroundColor = [UIColor whiteColor];
  webView.scalesPageToFit = YES;
  [self.view addSubview:webView];
}

But this causes another problem: your internal HTML page probably looks a lot smaller than you would like. To fix this we’ll use a trick that web app developers use to optimize web sites for the iPhone.

To the HTML code add a meta viewport tag:

<meta name="viewport" content="width=320"/>

The complete code looks like this:

NSString *html = @"<html><head><title>The Meaning of Life</title><meta name=\"viewport\" content=\"width=320\"/></head><body><p>...really is <b>42</b>!</p></body></html>";
[webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://www.hitchhiker.com/message"]];

written by Nick Dalton \\ tags: , ,

Mar 26

A UITextView is great for displaying multiple lines of simple text. But when you need something more fancy, like headlines or highlighting text, then you should look at UIWebView. It’s not just capable of displaying web pages from a URL, but you can also specify the HTML you want to display as a string.

Create a UIWebView in a controller:

- (void)loadView
{
  // Create a custom view hierarchy.
  CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
  UIView *view = [[UIView alloc] initWithFrame:appFrame];
  view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
  self.view = view;
  [view release];

  CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
  webView = [[UIWebView alloc] initWithFrame:webFrame];
  webView.backgroundColor = [UIColor whiteColor];
  [self.view addSubview:webView];
}

Then you can add your rich text to the view like this:

NSString *html = @"<html><head><title>The Meaning of Life</title></head><body><p>...really is <b>42</b>!</p></body></html>";
[webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://www.hitchhiker.com/message"]];

The documentation is not very clear on what the baseURL is used for in the context of HTML that is loaded from a string.

written by Nick Dalton \\ tags: ,