Archive for the 'I talk code' Category

A infinite/endless paging UIScrollView

Infinity is a very powerful concept, so maybe my post title shouldn’t include this term. Anyway, I tried to create something similar to a infinite or endless paging scroll view.

The idea is very simple:

  • Create a view including a standard scroll view.
  • Provide an interface to load views for each page on demand.
  • Cache views for pages (specify the maximum amount of cached pages).
  • If user scrolls the view load (and cache) the next and previous view.

You will find the source code of this component (I named it InfinitePagingView) and a example project at our github repository.

Using InfinitePagingView is very straightforward. Just implement the InfinitePagingDataSource protocol, create an instance of InfinitePagingView and add it to your current view:

InfinitePagingView *infinitePagingView = [[InfinitePagingView alloc]
            initWithFrame:CGRectMake(0, 0, 320, 480)
            andDataSource:self];
 
[self.view addSubview:infinitePagingView];
[infinitePagingView release];

After that -(UIView*) infinitePagingView:(InfinitePagingView*)infinitePagingView viewForPageIndex:(int)index gets called for each page and you can provide your custom view for the requested page.

Cheers,
Andreas

Transparent UIToolBar

Sometimes it is really necessary to have a transparent UIToolBar within you iPhone app. Especially if you want to add a UIToolBar to your UINavigationBar you get some problems with overlaying backgrounds (UIBarStyleBlackOpaque did not work for a toolbar on a black opaque navigation bar).

A quick and pragmatic solution is to subclass UIToolBar and do some modifications. The following code is everything you need to get a really transparent tool bar:

@interface TransparentToolbar : UIToolbar
@end
 
@implementation TransparentToolbar
 
// Override draw rect to avoid
// background coloring
- (void)drawRect:(CGRect)rect {
    // do nothing in here
}
 
// Set properties to make background
// translucent.
- (void) applyTranslucentBackground
{
	self.backgroundColor = [UIColor clearColor];
	self.opaque = NO;
	self.translucent = YES;
}
 
// Override init.
- (id) init
{
	self = [super init];
	[self applyTranslucentBackground];
	return self;
}
 
// Override initWithFrame.
- (id) initWithFrame:(CGRect) frame
{
	self = [super initWithFrame:frame];
	[self applyTranslucentBackground];
	return self;
}
 
@end

To apply a color to the including UIBarButtonItems you can set the bar style as usual.

That’s all for today,
Andreas

Multiple UIAccelerometer delegates

Sometimes there is a need to listen to the acceleration events of your device and sometimes there is need to listen multiple times to this events. The only trade-off is, that you can set only one delegate to the shared instance of UIAccelerometer.

For rare situations, multiple objects or controllers need to listen to acceleration events in parallel we need to provide a simple wrapper implementation which acts as an acceleration delegate and notifies subscribed observers. Such a wrapper I implemented on my own and you can find it at my github repository.

To use it just import Accelerometer.h and use the sharedInstance to add and remove new delegates. The following examples shows you that:

//Create observers which implement UIAccelerometerDelegate protocol
ObserverOne *one = [[[ObserverOne alloc] init] autorelease];
ObserverTwo *two = [[[ObserverTwo alloc] init] autorelease];
 
//Subscribe observers to acceleration events
[[Accelerometer sharedInstance] addDelegate:one];
[[Accelerometer sharedInstance] addDelegate:two];
 
... // some code goes here
 
//Unsubscribe observer from acceleration events
[[Accelerometer sharedInstance] removeDelegate:one];

The drawback of the current implementation is, that you can’t subscribe to different update intervals. For the moment each observer will be notified at the same interval.

Cheers,
Andreas

Show a custom popover view within your iPad App

The possibility to show popover views (modal or non modal) is a really cool thing within the new iPhone OS 3.2. It allows you to display important information, request some input from the user or present some kind of navigation structure. Anyway, it depends on your application but it helps to focus the user on your main content and to avoid too many context (or better: view layout) changes.

Now I am going to give you just a quick example of how we can display a customized popover view within our application. First of all I want to present a simple popover view when a given toolbar button was pressed. The class UIPopoverController offers the functionality to show a popover with any given view controller.

We are also able to limit the popover’s view size with the new property contentSizeForViewInPopover in all UIViewController classes. If you don’t customize this property, the popover will be shown in its default width of 320 px and in full screen height.

After initialization of your UIPopoverController instance you can call the method presentPopoverFromBarButtonItem: permittedArrowDirections: animated:. The first parameter is used to locate the control which creates the popover view. The second parameter permittedArrowDirections allows you to restrict the direction of the shown arrow of the popover. To support all orientations and layout changes, UIPopoverArrowDirectionAny is the best way to go.

-(void) toolbarAction:(id)sender {
   if([self.popoverController isPopoverVisible])
   {
      //close the popover view if toolbar button was touched
      //again and popover is already visible
      //Thanks to @chrisonhismac
 
      [self.popoverController dismissPopoverAnimated:YES];
      return;
   }
 
   //build our custom popover view
   UIViewController* popoverContent = [[UIViewController alloc]
                              init];
   UIView* popoverView = [[UIView alloc]
                        initWithFrame:CGRectMake(0, 0, 300, 400)];
   popoverView.backgroundColor = [UIColor blueColor];
   popoverContent.view = popoverView;
 
   //resize the popover view shown
   //in the current view to the view's size
   popoverContent.contentSizeForViewInPopover =
                              CGSizeMake(300, 400);
 
   //create a popover controller
   self.popoverController = [[UIPopoverController alloc]
               initWithContentViewController:popoverContent];
 
   //present the popover view non-modal with a
   //refrence to the toolbar button which was pressed
   [self.popoverController presentPopoverFromBarButtonItem:sender
               permittedArrowDirections:UIPopoverArrowDirectionUp
               animated:YES];
 
   //release the popover content
   [popoverView release];
   [popoverContent release];
}

In my example application I get the following screen:

So, while showing popover views from toolbar items is very common, it is also often necessary to show popovers when interacting with other UI controls within your screen. Another example will show a popover view triggered from a standard button within my main content view.

I placed a button called popoverButton which performs the following method when activated. This time we use the method presentPopoverFromRect and use the button’s frame as source for the direction of the popover’s arrow. The popover implementation is very sophisticated and places the popover so it fits best at the current screen.

-(void) buttonAction:(id)sender {
   //build our custom popover view
   UIViewController* popoverContent = [[UIViewController alloc]
                  init];
   UIView* popoverView = [[UIView alloc]
                  initWithFrame:CGRectMake(0, 0, 200, 300)];
   popoverView.backgroundColor = [UIColor greenColor];
   popoverContent.view = popoverView;
 
   //resize the popover view shown
   //in the current view to the view's size
   popoverContent.contentSizeForViewInPopover =
                  CGSizeMake(200, 300);
 
   //create a popover controller
   self.popoverController = [[UIPopoverController alloc]
               initWithContentViewController:popoverContent];
 
   //present the popover view non-modal with a
   //refrence to the button pressed within the current view
   [self.popoverController presentPopoverFromRect:popoverButton.frame
               inView:self.view
               permittedArrowDirections:UIPopoverArrowDirectionAny
               animated:YES];
 
   //release the popover content
   [popoverView release];
   [popoverContent release];
}

Using this code will create another popover which will look as shown in the picture below:

I really like popovers and also the possibility to show them in a modal manner. It is recommended to use modal popover views very rarely because the user’s focus gets lost from the main content. Use them only when it is really necessary and some kind of mandatory input is needed (i.e. accepting terms of use).

You will find the source code of this example at my github repository. The project is called PopoverView.

Cheers,
Andreas

Your first iPad split view application

The split view is something very cool within the new iPhone OS 3.2. It allows us to visualize a master-detail view in a very simple manner. Combined with iPads’ big display of 1024×748 pixels it will be possible to create even better, more user-friendly and valuable applications.

Basically, the split view consists of two separate views. The master view will be shown in a 320 pixel width part on your screen if your iPad is at landscape orientation, otherwise the master view will be accessible as a popover view. The details view should show your main content and will be at full size if your iPad is at portrait orientation. Mainly the user will be focused at your details view and this fact you should keep in mind.

Creating a split view pragmatically within your application is a easy task. The following code will show this:

//create the master view
MasterViewController *masterView = [[MasterViewController alloc]
                initWithNibName:@"Master"
                bundle:[NSBundle mainBundle]];
 
//create the details view
DetailsViewController *detailsView = [[DetailsViewController alloc]
                initWithNibName:@"Details"
                bundle:[NSBundle mainBundle]];
 
//create the split view
UISplitViewController *splitController =
                [[UISplitViewController alloc] init];
 
//set the view controllers array
splitController.viewControllers = [NSArray
                arrayWithObjects:masterView, detailsView, nil];
 
//show split view as the main view
[window addSubview:splitController.view];
[window makeKeyAndVisible];
 
//release view
[masterView release];
[detailsView release];

Next we want to access the master view via a popover view, when the iPad is in portrait mode. The shouldAutorotateToInterfaceOrientation: method of your master and detail controller must support all orientations, otherwise it wont be possible to rotate a split view. After that implement the UISplitViewControllerDelegate protocol in any class and set the delegate of your split view controller. The methods within this protocol will be called whenever the master view will be hidden or shown again.

In my example I created another class which gets a reference to the details view controller and holds the toolbar object we will use to present the popover button. The following code is pretty simple and contains the three methods of the UISplitViewControllerDelegate protocol. The first method is called whenever the master view will be hidden. So in this case we will add a toolbar with the given popover button to our detail view. You are free to label the button as you like. The second method is called whenever the master view will be shown again. Now we simply hide the toolbar. So, that’s pretty all. The displaying logic of your master view within a popover view is done automatically, but you can still modify it within the last method (which is empty in my case).

//the master view controller will be hidden
- (void)splitViewController:(UISplitViewController*)svc
    willHideViewController:(UIViewController *)aViewController
    withBarButtonItem:(UIBarButtonItem*)barButtonItem
    forPopoverController:(UIPopoverController*)pc {
 
  if(toolBar == nil) {
    //set title of master button
    barButtonItem.title = @"Show Master";
 
    //create a toolbar
    toolBar = [[UIToolbar alloc]
                    initWithFrame:CGRectMake(0, 0, 1024, 44)];
    [toolBar setItems:[NSArray arrayWithObject:barButtonItem]
                    animated:YES];
  }
 
  //add the toolbar to the details view
  [detailController.view addSubview:toolBar];
}
 
//the master view will be shown again
- (void)splitViewController:(UISplitViewController*)svc
    willShowViewController:(UIViewController *)aViewController
    invalidatingBarButtonItem:(UIBarButtonItem *)button {
 
  //remove the toolbar
  [toolBar removeFromSuperview];
}
 
// the master view controller will be displayed in a popover
- (void)splitViewController:(UISplitViewController*)svc
    popoverController:(UIPopoverController*)pc
    willPresentViewController:(UIViewController *)aViewController {
 
  //empty for now
 
}

Well, you need to do something more than this if you want to create really useful split view applications. Often it will be wise to use a table view as your master. Some things I found out while playing around with the split view are:

  • You are not able to present a split view as a modal view
  • If the master or detail view doesn’t allow all interface orientations, the split view will not work properly. So if you don’t see the master view check your shouldAutorotateToInterfaceOrientation method within your view controller.

You will find the source code of this example at my github repository. The project is called MasterDetail.

Cheers,
Andreas

Update:

Some people asked me if it is possible to keep the master view visible even in portrait mode. I tried around and found following working solution:

Create a subclass of UISplitViewController and just overwrite the method willAnimateRotationToInterfaceOrientation: duration:. This method will be called whenever the orientation of a view is going to be changed. Everything you have to do is to check if the interface will change to a portrait method and if that is true, adjust the visible frames of your master and detail views. Find below the code I used to get this working:

/**
 * Sent to the view controller just before
 * the user interface begins rotating.
 */
- (void)willAnimateRotationToInterfaceOrientation:
            (UIInterfaceOrientation)interfaceOrientation
            duration:(NSTimeInterval)duration {
 
      //get master and detail view controller
      UIViewController* master = [self.viewControllers objectAtIndex:0];
      UIViewController* detail = [self.viewControllers objectAtIndex:1];
 
      //only handle the interface orientation
      //of portrait mode
      if(interfaceOrientation == UIInterfaceOrientationPortrait ||
            interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
            //adjust master view
            CGRect f = master.view.frame;
            f.size.width = 320;
            f.size.height = 1024;
            f.origin.x = 0;
            f.origin.y = 0;
 
            [master.view setFrame:f];
 
            //adjust detail view
            f = detail.view.frame;
            f.size.width = 830;
            f.size.height = 1024;
            f.origin.x = 320;
            f.origin.y = 0;
 
            [detail.view setFrame:f];
      }
      else {
            //call super method
            [super willAnimateRotationToInterfaceOrientation:interfaceOrientation
                        duration:duration];
      }
}

Now, just use your own UISplitViewController subclass within your code and the master view should stay visible even in portrait mode. I hope this code may answer your questions and will be helpful for you.

Multilanguage support in your iPhone app

Since your app can be downloaded in almost every country of the world, the support of multiple languages is a crucial topic in app development. In this post I will show a simple example of how you can localize strings used within your app.

To consequently use the predefined foundation macros  within your code files is the best way to start. The macros (a detailed description can be found over here) are:

  • NSLocalizedString(key, comment)
  • NSLocalizedStringFromTable(key, tableName, comment)
  • NSLocalizedStringFromTableInBundle(key, tableName, bundle, comment)
  • NSLocalizedStringWithDefaultValue(key, tableName, bundle, value, comment)

The really best choice is to use NSLocalizedStringWithDefaultValue, because with this macro you are able to define your key and a corresponding default value. The default value should be the correct translation for the given key in your main development language. A simple example is:

NSLocalizedStringWithDefaultValue(@"firstname",
          nil,
          [NSBundle mainBundle],
          @"Firstname",
          @"user information");

As you can see, I want to get a translation for my key firstname. Since translations are stored in .strings files, the parameter tableName specifies the name of the file you want to search for the given key. If this parameter is empty the default Localizable.strings will be searched. Also you have to specify the bundle, where your localized resources reside. Mostly it will be the main bundle of your application. The next two parameters are default and comment which will be very useful as you will see soon.

So when using this macro, your application should be fully functional within your main development language. Before starting to translate your application you need to create some language specific folders within your application folder. These folders need to have the .lproj extension and their name should be the language abbreviation you want to support (i.e. en, de, fr, …).

Now there are two options to go. Either you create a Localizable.strings file in each .lproj directory and add your key-value-pairs manually or you generate the first .string file from you source code. Since we consequently used the predefined macros it is possible to use the command line tool genstrings to parse all your code files and create the corresponding .strings file. To do so, simply type in:

genstrings -o en.lproj Classes/*.m

After that you get your Localizable.strings file with following content:

/* user information */
"firstname" = "Firstname";

As you can see this is very simple. Also the given comment used within the macro call is visible within the generated code which allows you to keep records about your keys in a nice manner. Now you can simply copy your file to all other directories and translate them. The only trade-off you should keep in mind is that genstrings overwrites your file every time you call it. This means you should keep a copy of your files before calling genstrings again.

Multilanguage support within your .nib files or images is quite easy too, just create translated versions of your files and place them in the corresponding .lproj directory.

Tip:

If you are struggling with the localization and internationalization support within XCode, because it creates folders named like English.lproj, German.lproj, … then simply create the folders en.lproj, de.lproj, … within your application directory by your own. After that, place a file like Localizable.strings in your sub folders and then add the file within XCode to your project.

So that’s all folks and I hope you enjoyed this post.

Cheers,
Andreas

How to play a video within your iphone app

Sometimes you need to show a short sequence of a video file within your app to enrich your content. However, this is a very simple task. Everything you need is a H.264 or MPEG-4 video included in your project and you also have to reference the MediaPlayer framework. After that simply use the following code to start your video:

...
//specify the URL of the movie
NSURL *movieUrl = [NSURL fileURLWithPath:
            [[NSBundle mainBundle] pathForResource:@"mymovie" 
            ofType:@"m4v"]];
 
//create a new instance of MPMoviePlayerController
MPMoviePlayerController* myMovie=[[MPMoviePlayerController alloc] 
            initWithContentURL:movieUrl];
 
//disable scaling of our movie
myMovie.scalingMode = MPMovieScalingModeNone;
 
//don't show any controls
myMovie.movieControlMode = MPMovieControlModeHidden;
 
//you can specify at which time the movie should 
//start playing (default is 0.0)
myMovie.initialPlaybackTime = 2.0;
 
//register a callback method which will be called
//after the movie finished
[[NSNotificationCenter defaultCenter] addObserver:self 
            selector:@selector(movieFinished:) 
            name:MPMoviePlayerPlaybackDidFinishNotification 
            object:myMovie]; 
 
//start the movie (asynchronous method)
[myMovie play];
...

A callback method is used to release your media player instance, which you can simply add to your current class:

-(void)movieFinished:(NSNotification*)aNotification 
{
	//get the movie instance from the notification object
	MPMoviePlayerController* myMovie=[aNotification object]; 
	[[NSNotificationCenter defaultCenter] removeObserver:self 
                    name:MPMoviePlayerPlaybackDidFinishNotification 
                    object:myMovie]; 
 
	//release the movie
	[myMovie release]; 
}

And that’s all folks. The code shown above works with iPhone OS 2.0 or greater. In the next release of the iPhone OS there maybe will be some more enhancements on playing movies within your app.

Cheers,

Andreas

Hide iPhone status bar

Hi folks,

today something very short and simple. There are two ways to hide your status bar within your iPhone app:

  1. Programmatically
    ...
    //use this whereever you want
    [[UIApplication sharedApplication] setStatusBarHidden:YES
                                       animated:NO];
    ...
  2. Configuration of your Info.plist (seen in SDK 3.1.2)
    Just add a new line to your "your project name"-Info.plist file and select "Status bar is initially hidden" like in the picture below.

Thats pretty all! Have fun,
Andreas

Custom video/camera overlay view on the iPhone

Today I am going to show how we can add a custom overlay view to the standard iPhone video capturing functionality. First of all I have to say, that since the iPhone OS 3.1 is published, a custom overlay is really simple to achieve. There are only a few steps you have to do:
Continue reading ‘Custom video/camera overlay view on the iPhone’

Set background image of UITableView

How to set a background image of a UITableView is a very often and common question. Today we will try to answer this.

There are two ways to solve this problem:

  1. Create a new UIView – lets call the view V – set the background image of V and embed a UITableView – lets call it TV – within V. Now set the background color of TV to [UIColor clearColor] and do so for all UITableViewCells. Everything seems to work well but you have to handle some tasks (regarding the UITableView) on your own now like deselcting the currently selected UITableViewCell when returning from a prior pushed view.
  2. The second approach requires less effort but creates a not so pretty side-effect. You can simply create a new UIView, set its background image and send this view to the back of the UITableView. If you do so the background image scrolls with the UITableView. So this solution should only be used if you do not have to many cells, i.e. to create a simple menu screen in a grouped style within your app.

For those guys, implementing the second solution, the following code would be helpful. Put it i.e. in your - (void) viewDidLoad; method or further initialization of your view controller.

Continue reading ‘Set background image of UITableView’