[TutorialSystem showTutorialForKey:@"Welcome"];
The
TutorialSystem
class takes over the rest through a series of class methods. (There's never an instance of a TutorialSystem
object. Not a very object-oriented approach, but the tutorial system doesn't need to maintain state between invocations.)Obviously I only want to show a tutorial screen once, so
showTutorialForKey:
first checks to see if the user has already seen the screen. I have an "application state" dictionary file that gets used for miscellaneous persistence: the last tab the user looked at before shutting down, the date they were looking at in the "by day" view, and so forth. The tutorial system uses the same dictionary to keep track of which tutorial screens the user has seen. In particular, it looks for a key named "hasSeen" followed by the name of the key passed in to the showTutorialForKey
method. For the example above, the dictionary would have a key named "hasSeenWelcome."
+ (BOOL) userHasSeenKey: (NSString *)key {
if (ALWAYS_SHOW_HELP) {
return NO;
}
NSMutableDictionary *prefs = [[TutorialSystem appDelegate] appState];
NSNumber *didSee = [prefs objectForKey:[TutorialSystem prefsSeenKeyForKey:key]];
return didSee != nil && [didSee intValue] != 0;
}
(I have a #define that lets me always have tutorial screens show up. This is helpful for testing.)
If the system decides that it needs to show the tutorial screen, it uses the passed-in key as the key for a line in a strings file, the resource files Cocoa uses for localization of text. It also uses the key plus the text " Title" as the key in the strings file for the title of the tutorial screen. That means there's a line in my strings file that maps the tutorial body text to the key "Welcome" and another line that maps the tutorial screen title to "Welcome Title."
From there, it loads an xib file that I built in Interface Builder and lays it over the existing view. That file contains a screen-sized view that doesn't allow user interaction, but has an opaqueness level of .4. That way the underlying screen will still be visible. The xib file also contains a "tutorial screen" view that contains three subviews: a UILabel for the title, a UITextView for the tutorial body, and a UILabel that says "Tap to continue." The tutorial screen view handles all the user interactions, and interprets any touch to mean "go away." Here's what it looks like.
Finally, of course, I register that the user has seen the tutorial screen by placing the appropriate entry into the application state dictionary.
Here's the full
showTutorialForKey:
method:
+ (void) showTutorialForKey: (NSString *)key {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if ([TutorialSystem userHasSeenKey:key]) {
[pool release];
return;
}
NSString *titleKey = [NSString stringWithFormat:@"%@ Title",key];
NSString* title = [[NSBundle mainBundle]
localizedStringForKey:titleKey value:@"" table:@"Tutorial"];
NSString* text = [[NSBundle mainBundle]
localizedStringForKey:key value:@"" table:@"Tutorial"];
TutorialController *controller =
[[TutorialController alloc] initWithTitle:title tutorialText:text];
[[[self appDelegate] window] addSubview:[controller view]];
[TutorialSystem registerUserSeesKey:key];
[pool release];
}
I wrote another Tutorial system for the iphone which simply points out buttons with arrows and text. You can download it from github - http://appsinheaven.wordpress.com/2010/03/02/iphone-tutorial-system/
ReplyDelete