Removing pesky UITableView lines
You know how, if you have a UITableView with only a few entries, how the divider lines for the empty (non-existent) cells still show up? This happens to me every once in a while, and every time I always have to go look up the solution. Well in case you’re wondering, it’s as easy as one line of code:
mTableView.tableFooterView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
And that’s it. Happy coding!
Slide-Away Screens
In an app I’m working on now I thought I’d give the slide-away screen metaphor a try. Like the one found in the Path and Facebook apps. So I went online and sought a library that could do that for me. Many of the libraries I found were actually for the iPad, and mimicked the behaviour of the Twitter app. Close, but not what I wanted. I found a few libraries, but many of them didn’t support swiping. They were only controlled by a button or some other event.
Finally I found DDMenuController, which seemed to fit what I wanted to do. I experimented with it a bit, and it was easy enough to use. I could also tweak the source code to change how much of the “underneath” controller would show. This was important because I only wanted to show a narrow strip of controls, which isn’t very wide. But soon enough I discovered bugs. Often on a swipe, the underneath controller wouldn’t show at all, but rather it would just be black. I fiddled with the source code a bit and finally got that to happen a lot less often. But when I added a second underneath controller on the right side, the problem came back with a vengeance, and at that point I just gave up.
I looked around again, and found a library I didn’t find the first time. It’s called ViewDeck. So far, I haven’t encountered any bugs, which is good. But I haven’t yet found a way to change how far the main screen moves over. Well, that’s not quite true. I did find something for that, but when I set it to a value I like, the main screen just bounces back and doesn’t stay in the slid-over position. So I’m going to play around with it a little bit and post an update with what I found.
UPDATE 1: I found the solution. It’s just a matter of making sure the rightLedge is large enough to trigger the left edge to stay in place. I’m hoping this works out later when I’ll want a small left underneath view and a large right underneath view.
UPDATE 2: As it turns out, trying to have a large right view was problematic. But I changed the source code to fix that. In (void)panned:(UIPanGestureRecognizer*)panner there’s a divsion by 3.0. I changed that to 4.0 and that made it work.
Remove Tab Bar When Controller Pushed
Sometimes it’s the little tips that prove really useful, and as such, I present one today. This would have helped me out greatly about three months ago. If you have a UITabBarController, and you’re pushing a new controller in a UINavigationController which is one of the tabs, typically the tab bar across the bottom stays in place. But you can remove it quite easily with this line of code:
[self.navigationController pushViewController:controller animated:YES];
I just discovered this recently, and have already made use of it. Good luck.
Pattern for Loading Table Data
I gave this pattern to a coworker of mine the other day, and they thought it was quite helpful. Starting iPhone develops may be just getting used to how things work on the iPhone, so I thought I’d point out a good way to load a lot of data into a table view.
{
// this must be done on main thread
// stop spinner here using self.view
[mTableView reloadData];
}
- (void) startup
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// load the data here
[pool release];
[self performSelectorOnMainThread:@selector(finishStartup) withObject:nil waitUntilDone:NO];
}
- (void)viewDidLoad {
[super viewDidLoad];
// start spinner here using self.view
[self performSelectorInBackground:@selector(startup) withObject:nil];
}
You have to remember that GUI stuff like starting and stopping spinners and reloading the table view have to be done on the main thread.
You can’t just do something like this:
[super viewDidLoad];
// start spinner here using self.view
// load data
// stop spinner
[mTableView reloadData];
}
Why? Because the spinner never gets a chance to be processed and shown. That’s a general pattern whenever you want to show the spinner. You have to start it in the main thread and do your processing independently.
Custom Button in NavBar
Just a quick snippet of code for you guys today.
Ever wanted to know how to put a custom image into the navigation bar? It’s actually pretty easy. Create a UIButton object, and stick that into the UIBarButtonItem object. The trick is to remember to set the size:
image = [UIImage imageNamed:@"button_plus.png"];
[add setImage:image forState:UIControlStateNormal];
image = [UIImage imageNamed:@"button_plus_selected.png"];
[add setImage:image forState:UIControlStateSelected];
add.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
[add addTarget:self action:@selector(onAdd) forControlEvents:UIControlEventTouchUpInside];
addButton = [[UIBarButtonItem alloc] initWithCustomView:add];
self.navigationItem.rightBarButtonItem = addButton;
And Bob’s your uncle!
Fading an Image into Another
My Pollen project required that I be able to have an image, and fade it into another image. Other projects since then have also had similar requirements. The effect is very nice, and the great thing is that the code is really quite simple. Just have two images, and do an animation from one to the other. I like have one image always being the active one (when not animating), so that’s how I structured the code below. I assume you have two UIImageView’s set up named mFrontView and mBackView.
UIImage *oldImg = mFrontView.image;
if ( newImg != oldImg )
{
[mBackView setImage:mFrontView.image];
mFrontView.alpha = 0;
mBackView.alpha = 1;
[mFrontView setImage:newImg];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
mFrontView.alpha = 1;
mBackView.alpha = 0;
[UIView commitAnimations];
}
Fixing Broken Pipes
There’s nothing like the simulator for putting your app together quickly. It’s better than debugging on the device for one main reason: it’s fast! Starting up the app is fast. Debugging the app is fast. Everything is fast.
But sometimes you just need to slow down. By using the device. Of course, I was testing on the device today and made a critical error.
I couldn’t figure out what was wrong. I was getting error messages in the debugger console like this:
putpkt: write failed: Broken pipe
Or this:
mem 0×1000 0x3fffffff cache
mem 0×40000000 0xffffffff none
mem 0×00000000 0x0fff none
Or even like this:
Sent: [1251990710.449:32] +
Sent: [1251990710.449:32] Hc-1
Recvd: [1251990710.454:32] OK
Sent: [1251990710.455:32] qC
Recvd: [1251990710.460:32] QC0
Sent: [1251990710.460:32] qStepPacketSupported
Recvd: [1251990710.463:32] OK
Sent: [1251990710.478:49] QEnvironment:SHELL=/bin/bash
Recvd: [1251990710.481:49] OK
Sent: [1251990710.481:49] QEnvironment:TMPDIR=/var/folders/UF/UFCJNauIGPu+F7L7bsqhZU+++TI/-Tmp-/
Recvd: [1251990710.485:49] OK
Sent: [1251990710.485:49] QEnvironment:Apple_PubSub_Socket_Render=/tmp/launch-o19tpZ/Render
Recvd: [1251990710.488:49] OK
etc…..
It was quite frustrating.
So I looked around on the forums, and there were several questions about these errors, many of which went unanswered. (Forums can only get you so far sometimes.) But eventually I found the answer: you can’t debug your program if you’re using an ad hoc profile.
So I used the appropriate profile, and now I debug to my heart’s content. iPhone development seems to be straining with this kinds of gotchas. I just hope I remember this solution next time I find this problem. Writing it down will help, I hope!
Images in a Scroll View
I know that when I was a beginning iPhone developer doing things that seem so simple now weren’t so simple back then. Just because I didn’t know any better and was unaware of the tools and API’s available to me.
One thing that I’ve been doing a lot recently is putting several images in a UIScrollView, so I thought I’d post the barebones version of the code here in case anyone finds it useful. Hopefully I’ll be able to add more snippets in the future.
#define IMAGE_HEIGHT 416
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *photos = nil; // TODO – fill with your photos
// note that the view contains a UIScrollView in aScrollView
int i=0;
for ( NSString *image in photos )
{
UIImage *image = [UIImage imageNamed:[photos objectAtIndex:i]];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = YES;
imageView.frame = CGRectMake( IMAGE_WIDTH * i++, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
[aScrollView addSubview:imageView];
[imageView release];
}
aScrollView.contentSize = CGSizeMake(IMAGE_WIDTH*i, IMAGE_HEIGHT);
aScrollView.delegate = self;
}
