Browsing articles in "Blog"

Efficient and streamlined forms

May 19, 2011   //   by Romain Vincens   //   Blog  //  1 Comment

In many projects I had to implement a login screen, containing two text fields: one for the username, and one for the password. It’s as easy as dropping two textfields on a view, creating the outlets and writing a few lines of code. But when it comes to make your interaction between the form and your user as smooth, efficient and streamlined as possible, you need to write some additional lines of code.

1. Cycle through fields

The user has entered his username, he now needs to edit the password. It’s as easy as tapping the second textfield. But power-users want to go fast, they want to continue tapping without moving too much the fingers on screen. So you decide to set the returnKeyType of your textfields to UIReturnKeyNext. And once both fields are filled (and possibly validation passed), you can launch the authentication process.

Here’s a example for such code:

- (BOOL) textFieldShouldReturn:(UITextField *)textField {

	BOOL loginEntered = !(self.loginField.text == nil || [self.loginField.text isEqualToString:@""]);
	BOOL passwordEntered = !(self.passwordField.text == nil || [self.passwordField.text isEqualToString:@""]);

	if(textField == self.loginField) {
		if(!passwordEntered) {
			[self.loginField resignFirstResponder];
			[self.passwordField becomeFirstResponder];
			return YES;
		}
		else if(!loginEntered) {
			return NO;
		}
	}

	if(textField == self.passwordField) {
		if(!loginEntered) {
			[self.passwordField resignFirstResponder];
			[self.loginField becomeFirstResponder];
			return YES;
		} else if(!passwordEntered) {
			return NO;
		}
	}

    // Start your authentication process
    .....

	return YES;
}

Of cours both text fields have their delegate set to your view controller. You can also auto-enable the return key on fields.
However no matter what the user has entered in the textfields, the keyboard always shows ‘Next’ as the return key.

2. On-the-fly keyboard return key type change

We’d like to have the ‘Go’ return key in the keyboard instead of ‘Next’ when both fields are validated and the user can start the authentication process. But the SDK comes with a limitation: changing the returnKeyType in the textFieldShouldReturn: method does not update the UI. Here’s the trick: use reloadInputViews.

Listen for textfields updates, for instance in your viewDidLoad: method in your controller:

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldDidChange:)
												 name:UITextFieldTextDidChangeNotification object:self.loginField];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldDidChange:)
												 name:UITextFieldTextDidChangeNotification object:self.passwordField];

Implement the textFieldDidChange: method

- (void) textFieldDidChange:(NSNotification*)notif {
	BOOL loginEntered = !(self.loginField.text == nil || [self.loginField.text isEqualToString:@""]);
	BOOL passwordEntered = !(self.passwordField.text == nil || [self.passwordField.text isEqualToString:@""]);

    UIReturnKeyType keyType = loginEntered && passwordEntered ? UIReturnKeyGo : UIReturnKeyNext;

    BOOL loginReturnTypeChanged = self.loginField.returnKeyType != keyType;
    BOOL passwordReturnTypeChanged = self.passwordField.returnKeyType != keyType;

    self.loginField.returnKeyType = keyType;
    self.passwordField.returnKeyType = keyType;

    if(loginReturnTypeChanged)
        [self.loginField reloadInputViews];

    if(passwordReturnTypeChanged)
        [self.passwordField reloadInputViews];
}

Do not forget to remove your notification observer, in viewDidUnload:

	[[NSNotificationCenter defaultCenter] removeObserver:self];

Et voilà, you now have a login form that do not require the user to tap anywhere outside of the keyboard. If you have other kind of tips, for making forms more efficient, please share!

(You can get a demo project here)

Slides et démo de la présentation CoreAnimation aux Cocoaheads

Mar 21, 2011   //   by Romain Vincens   //   Blog  //  No Comments

Cocoaheads

Le 10 mars, j’ai fait une présentation aux Cocoaheads Paris sur CoreAnimation. La présentation couvrait l’utilisation que l’on pouvait en faire au niveau UIKit jusqu’au niveau CALayer, et se terminait par l’animation de properties custom.
Si vous cherchez un projet démo pour mon précédent article «Animate CALayer custom properties with CoreAnimation», vous trouverez votre bonheur sur ce blog post:
http://cocoaheads.fr/2011/03/slides-et-sources-du-cocoaheads-de-mars-a-paris

Custom UITableViewCells loaded from XIB, howto & debug

Jan 4, 2011   //   by Romain Vincens   //   Blog  //  3 Comments

There is a lot of literature which can be found on the net about how to load UITableViewCells from XIB files, for a use in UITableViews. You can find at least 3 or 4 different methods to achieve it, and everyone is convince their method is better than other’s.

The Apple way

While I’m not interested now in debating which is best, it looks to me there’s a lot of confusion about how to achieve it right and quickly, so I am going to detail the one that Apple present as the official way.
An example is worth a thousand words, this one is taken from the Recipes example in Apple documentation:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *IngredientsCellIdentifier = @"IngredientsCell";

    EditingTableViewCell *cell = (EditingTableViewCell *)[tableView dequeueReusableCellWithIdentifier:IngredientsCellIdentifier];
    if (cell == nil) {
		[[NSBundle mainBundle] loadNibNamed:@"EditingTableViewCell" owner:self options:nil];
        cell = editingTableViewCell;
		self.editingTableViewCell = nil;
    }

    ....

}

The three interesting lines are located inside the if block. While they look strange at first, you get all the meaning once you open EditingTableViewCell.xib and see how things got laid down:

The type of the view (the class) is EditingTableViewCell. IBOutlets are mapped to that file. However, the File’s Owner is IngredientDetailViewController, which is the view controller managing the UITableView displaying the EditingTableViewCell.

Right-clicking the File’s Owner shows that EditingTableViewCell is mapped to an IBOutlet called editingTableViewCell in the controller.

Giving a quick look at IngredientDetailViewController.h shows the outlet:

@property (nonatomic, assign) IBOutlet EditingTableViewCell *editingTableViewCell;

That means that when the code calls

[[NSBundle mainBundle] loadNibNamed:@"EditingTableViewCell" owner:self options:nil];

the EditingTableViewCell XIB file is going to be loaded and attached to the self (the owner), in the editingTableViewCell ivar.

cell = editingTableViewCell;

keeps a reference to that loaded XIB, which is a EditingTableViewCell object, and then

self.editingTableViewCell = nil;

resets the outlet, so that it frees up unneeded memory. The cells will be queued and reused in the UITableView, and in case the view controller needs a new reference, it can load it again from the XIB.

Smart. Efficient.

Reusing in other view controllers

The downside is that the EditingTableViewCell XIB is associated to IngredientDetailViewController which is not nice if you want to reuse your XIB for a UITableView in another controller.

Duplicating the file is not a solution. In fact, you can load the XIB from another controller, as long as the outlet is named exactly the same. Even if it’s the original controller which is mentioned as the File’s Owner in the XIB, it works.

Debugging a blank view controller

There’s a common mistake in the class/xib setup that can lead to hours of debugging while all was going smooth a few seconds before. When creating your custom UITableViewCell XIB file, you enter the view controller’s name in the File’s Owner (4th tab in the Inspector).
Then you link the outlet to your view, but you should not link the view controller’s view to your view in that XIB. Instead it must remain blank (it will be mapped by the XIB of the view controller).

Do not link your controller's view outlet in a custom UITableViewCell's XIB file, or you will likely get bugs

Linking the view as well in the cell’s XIB will cause your view controller to appear blank when running the application. This is due to the conflict that the view controller’s view is linked in two different XIBs, and XCode doesn’t show any warning for this. You’re now warned.

Pages:1234»

Blog Categories