Showing posts with label Xcode. Show all posts
Showing posts with label Xcode. Show all posts

Saturday, December 14, 2013

iOS: Logo Image in Navigation Bar

One of the most frustrating things about developing for iOS is that you can do powerful things without breaking a sweat (e.g. animation), but sometimes getting the simplest things right involves a painful process of tweaking, scouring the internet and head-banging experimentation.

I recently wanted to display a logo image in the navigation bar of one of my screens. Sounds simple, right? Well it very nearly is, as there's a property self.navigationItem.titleView that is available in your view controller. Create an image view for your logo image, and use it to set this titleView property. Piece of cake.

Well, not quite. Problem is, the logo can end up blurry, and fail to resize correctly when you rotate the iPhone / iPad. And it turns out solving those two issues is not straightforward.

Since I've found the magic formula that makes iOS display a nice, sharp and correctly-sized navigation image on all devices and versions (tested v5 and up), I thought I'd share it. It goes like this:

Navigation Logo


1. Create an image called navigation-logo.png with height of 44 pixels - any width is fine. Create another image called navigation-logo@2x.png with height of 88 pixels - again, any width is fine. Add them to your XCode project.

2. In your view controller's viewDidLoad method, add the following:
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    UIImageView *imageView = [[UIImageView alloc]
        initWithFrame:CGRectMake(0,0,3,44)];
    imageView.contentMode = UIViewContentModeScaleAspectFill;
    imageView.clipsToBounds = NO;
    imageView.image = [UIImage imageNamed:@"navigation-logo"];
    controller.navigationItem.titleView = imageView;
}

Note we use a width of 3 for the UIImageView. This is important - if it's 2 (or any even number), then the image will be blurry. Setting clipToBounds=NO and contentMode=UIViewContentModeScaleAspectFill means the image will display outside the image view's width (fine), and will be correctly proportioned.

And that's all there is to it. Simple when you know how...

Thursday, November 21, 2013

iOS: Gotchas

Here's a couple of things that tripped me up today while developing an iOS app:

1. Views Blocking Touches

If you drag a plain view onto your view controller in storyboard, it will stop all touches reaching views located underneath. You will need to ensure the User Interaction Enabled setting is unchecked if you want your touches to be passed through.

2. Tap and Drag Location Tracking

Storyboard lets you easily wire up your buttons to methods in your view controller that get called whenever a user taps or drags inside the button. If you use Storyboard to create the stub method for you by dragging in the connection to an empty space in your view controller, it will create a method like:
- (IBAction)editClicked:(id)sender;
However, you may want to know where the user touched. Fortunately, this is easily available - just ensure you select the Sender and Event option in the Arguments drop-down when create the connection in Storyboard. This will then auto-create a method in your header file like:
- (IBAction)editClicked:(id)sender forEvent:(UIEvent *)event;
You can then get the touch position with the following code:
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint pointTouched = [touch locationInView:self.view];