Je pensais prendre une pause de la substance OpenGL pour finir un post j'ai pensé à faire pendant un moment. Une idée fausse que beaucoup de nouveaux développeurs Cocoa Touch / cacao semblent avoir, c'est que vos classes contrôleur d'application doivent être complètement personnalisé. Il ya quelque fondement de cette croyance, comme chaque application aura besoin d'avoir certaines fonctionnalités qui sont spécifiques à lui-même, mais il ya un certain nombre de génériques, les classes de contrôleur réutilisables, tels que UITableViewController et UINavigationController qui gèrent certains ou tous les aspects impliqués dans la commande d'un certain type d'interface utilisateur.
Pourtant, beaucoup de personnes ne portent pas cette idée de réutilisation dans leur code propre contrôleur pour une raison quelconque. Trop souvent, vous voyez des projets avec les classes de contrôleur de plusieurs qui sont tous très semblables les uns aux autres. Un endroit que j'ai vu ce lot a est quand les gens en œuvre basée sur des tables de montage vues détails comme ceux utilisés dans l'application Contacts. Voici un exemple de ce dont je parle:

Je suis honnêtement surpris que Apple ne fournit pas une classe contrôleur générique pour ce scénario particulier, mais ils n'en ont pas. Il n'y a aucune raison pour laquelle nous ne pouvons pas créer notre propre classe générique modifiable contrôleur de détails volet.
Je vais donner le code pour une version que j'ai utilisé dans quelques projets. Il permet l'édition de cinq champs de texte. La seule raison pour cinq champs est pris en charge parce que c'est tout ce qui peut être affiché avec le clavier. Si vous avez besoin de plus de cinq champs, vous devriez probablement scinder en bas forage multiples.
Pour utiliser cette classe, vous créez le contrôleur et placez-vous en tant que délégué. Vous pouvez alors définir trois propriétés. Les trois tableaux représentent les champs à afficher, donc l'élément à l'index 0 dans les trois tableaux sont des données différentes sur le même domaine, comme ceci:
FieldNames doit contenir l'étiquette pour être utilisé par le contrôleur de détail pour chaque élément. Ceci est le texte en bleu dans la capture d'écran ci-dessus que l'utilisateur voit. Le fieldKeys est la clé qui correspond à chaque domaine. Ce sera généralement le nom de propriété pour le terrain en cours d'édition, et sera utilisé dans la méthode qui est utilisée pour transmettre des valeurs de retour au délégué. FieldValues tiendra les valeurs actuelles de chacun des champs. Tous deux sans trois de ces propriétés doivent être définies, et elles doivent être NSArrays ou une sous-classe de celle-ci. Tous les trois doivent contenir le même nombre d'objets, et tous les trois doivent contenir cinq objets ou moins.
Il ya une autre propriété facultative que vous pouvez définir: keyboardTypes, qui est un tableau de cinq éléments UIKeyboardTypes. Ceci peut être utilisé pour indiquer au contrôleur de détail ce type de clavier pour montrer à l'utilisateur pour chaque champ qui peut être édité. Ces défaut à tous les UIKeyboardTypeAlphabet, mais si, par exemple, l'une des valeurs que vous souhaitez modifier le numéro de téléphone est, vous pouvez passer UIKeyboardTypePhonePad pour l'indice de tableau qui correspond à ce domaine.
Notez que dans la pseudo-code ci-dessus que nous avons mis l'auto en tant que délégué du contrôleur. Voilà comment nous en seront avisés si l'utilisateur éditée tous les champs. Le valuesDidChange: méthode sera appelée sur le délégué, en passant un dictionnaire en utilisant le codage clé-valeur qui informe le délégué de l'ensemble des modifications apportées si l'utilisateur appuyait sur le bouton Enregistrer. Le délégué est alors chargé de prendre les valeurs de ce tableau et les bourrant à l'endroit approprié.
Cette classe n'est pas aussi poli et n'a pas été testé à fond comme des classes d'Apple contrôleur générique, mais il a certainement réduit le nombre de classes de contrôleur dont j'ai besoin dans certains de ma table des applications basées sur. Alors, sans plus tarder, voici qu'elle est:
TextFieldEditingViewController.h
TextFieldEditingViewController.m
Pourtant, beaucoup de personnes ne portent pas cette idée de réutilisation dans leur code propre contrôleur pour une raison quelconque. Trop souvent, vous voyez des projets avec les classes de contrôleur de plusieurs qui sont tous très semblables les uns aux autres. Un endroit que j'ai vu ce lot a est quand les gens en œuvre basée sur des tables de montage vues détails comme ceux utilisés dans l'application Contacts. Voici un exemple de ce dont je parle:
Je suis honnêtement surpris que Apple ne fournit pas une classe contrôleur générique pour ce scénario particulier, mais ils n'en ont pas. Il n'y a aucune raison pour laquelle nous ne pouvons pas créer notre propre classe générique modifiable contrôleur de détails volet.
Je vais donner le code pour une version que j'ai utilisé dans quelques projets. Il permet l'édition de cinq champs de texte. La seule raison pour cinq champs est pris en charge parce que c'est tout ce qui peut être affiché avec le clavier. Si vous avez besoin de plus de cinq champs, vous devriez probablement scinder en bas forage multiples.
Pour utiliser cette classe, vous créez le contrôleur et placez-vous en tant que délégué. Vous pouvez alors définir trois propriétés. Les trois tableaux représentent les champs à afficher, donc l'élément à l'index 0 dans les trois tableaux sont des données différentes sur le même domaine, comme ceci:
TextFieldEditingViewController *controller = [[TextFieldEditingViewController alloc] initWithStyle:UITableViewStyleGrouped];
controller.delegate = self;
controller.fieldNames = myArrayContainingTheLabelsToBeDisplayed;
controller.fieldKeys = myArrayContainingTheKeyValuesForTheItemToBeDisplayed;
controller.fieldValues = myArrayContainingTheCurrentValuesForTheItemsToBeDisplayed;FieldNames doit contenir l'étiquette pour être utilisé par le contrôleur de détail pour chaque élément. Ceci est le texte en bleu dans la capture d'écran ci-dessus que l'utilisateur voit. Le fieldKeys est la clé qui correspond à chaque domaine. Ce sera généralement le nom de propriété pour le terrain en cours d'édition, et sera utilisé dans la méthode qui est utilisée pour transmettre des valeurs de retour au délégué. FieldValues tiendra les valeurs actuelles de chacun des champs. Tous deux sans trois de ces propriétés doivent être définies, et elles doivent être NSArrays ou une sous-classe de celle-ci. Tous les trois doivent contenir le même nombre d'objets, et tous les trois doivent contenir cinq objets ou moins.
Il ya une autre propriété facultative que vous pouvez définir: keyboardTypes, qui est un tableau de cinq éléments UIKeyboardTypes. Ceci peut être utilisé pour indiquer au contrôleur de détail ce type de clavier pour montrer à l'utilisateur pour chaque champ qui peut être édité. Ces défaut à tous les UIKeyboardTypeAlphabet, mais si, par exemple, l'une des valeurs que vous souhaitez modifier le numéro de téléphone est, vous pouvez passer UIKeyboardTypePhonePad pour l'indice de tableau qui correspond à ce domaine.
Notez que dans la pseudo-code ci-dessus que nous avons mis l'auto en tant que délégué du contrôleur. Voilà comment nous en seront avisés si l'utilisateur éditée tous les champs. Le valuesDidChange: méthode sera appelée sur le délégué, en passant un dictionnaire en utilisant le codage clé-valeur qui informe le délégué de l'ensemble des modifications apportées si l'utilisateur appuyait sur le bouton Enregistrer. Le délégué est alors chargé de prendre les valeurs de ce tableau et les bourrant à l'endroit approprié.
Cette classe n'est pas aussi poli et n'a pas été testé à fond comme des classes d'Apple contrôleur générique, mais il a certainement réduit le nombre de classes de contrôleur dont j'ai besoin dans certains de ma table des applications basées sur. Alors, sans plus tarder, voici qu'elle est:
TextFieldEditingViewController.h
/*
TextFieldEditingViewController.h
*/
#import <UIKit/UIKit.h>
#define kDefaultLabelTag 50002
@protocol TextFieldEditingViewControllerDelegate <NSObject>
@required
- (void)valuesDidChange:(NSDictionary *)newValues;
- (UINavigationController *)navController; // Return the navigation controller
@end
@interface TextFieldEditingViewController : UITableViewController <UITextFieldDelegate> {
NSArray *fieldNames; // Field name to be displayed to user
NSArray *fieldKeys; // Key value to be used in dictionary when values are passed back to delegate
NSArray *fieldValues; // Starting display values for each field. Values should be strings.
NSMutableArray *changedValues; // Changes will be stored in this array , which will also be passed back to delegate on save
UIKeyboardType keyboardTypes[5]; // Keyboard types for each field
id <TextFieldEditingViewControllerDelegate> delegate; // Delegate who will received the changed values. Delegate
// is responsble for converting back from string if necessary
UITextField *textFieldBeingEdited; // The field currently being edited
UIBarButtonItem *oldLeftButton; // Used to restore old button values
UIBarButtonItem *oldRightButton;
}
@property (nonatomic, retain) NSArray *fieldNames;
@property (nonatomic, retain) NSArray *fieldKeys;
@property (nonatomic, retain) NSArray *fieldValues;
@property (nonatomic, retain) NSMutableArray *changedValues;
@property (nonatomic, assign /* for weak ref */) id <TextFieldEditingViewControllerDelegate> delegate;
@property (nonatomic, retain) UITextField *textFieldBeingEdited;
@property (nonatomic, retain) UIBarButtonItem *oldLeftButton;
@property (nonatomic, retain) UIBarButtonItem *oldRightButton;
-(IBAction)cancel;
-(IBAction)save;
-(IBAction)textFieldDone:(id)sender;
-(void)setKeyboardType:(UIKeyboardType)theType forIndex:(NSUInteger)index;
@end
TextFieldEditingViewController.m
/*
TextFieldEditingViewController.m
*/
#import "TextFieldEditingViewController.h"
#import "BirthdaysAppDelegate.h"
@implementation TextFieldEditingViewController
@synthesize fieldNames;
@synthesize fieldKeys;
@synthesize fieldValues;
@synthesize delegate;
@synthesize changedValues;
@synthesize textFieldBeingEdited;
@synthesize oldLeftButton;
@synthesize oldRightButton;
- (id)initWithStyle:(UITableViewStyle)style
{
if (self = [super initWithStyle:style])
{
for (int i =0; i < 5; i++)
keyboardTypes[i] = UIKeyboardTypeAlphabet;
}
return self;
}
-(IBAction)textFieldDone:(id)sender
{
UITableViewCell *cell = (UITableViewCell *)[[(UIView *)sender superview] superview];
UITableView *table = (UITableView *)[cell superview];
NSIndexPath *textFieldIndexPath = [table indexPathForCell:cell];
NSUInteger row = [textFieldIndexPath row];
row++;
if (row >= [fieldNames count])
row = 0;
NSUInteger newIndex[] = {0, row};
NSIndexPath *newPath = [[NSIndexPath alloc] initWithIndexes:newIndex length:2];
UITableViewCell *nextCell = [self.tableView cellForRowAtIndexPath:newPath];
UITextField *nextField = nil;
for (UIView *oneView in nextCell.contentView.subviews)
{
if ([oneView isMemberOfClass:[UITextField class]])
nextField = (UITextField *)oneView;
}
[nextField becomeFirstResponder];
}
- (void)viewWillAppear:(BOOL)animated
{
self.oldLeftButton = self.navigationItem.leftBarButtonItem;
self.oldRightButton = self.navigationItem.rightBarButtonItem;
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
initWithTitle:@"Save"
style:UIBarButtonItemStylePlain
target:self
action:@selector(save)];
self.navigationItem.rightBarButtonItem = saveButton;
[saveButton release];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]
initWithTitle:@"Cancel"
style:UIBarButtonItemStylePlain
target:self
action:@selector(cancel)];
self.navigationItem.leftBarButtonItem = cancelButton;
[cancelButton release];
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
self.navigationItem.leftBarButtonItem = oldLeftButton;
self.navigationItem.rightBarButtonItem = oldRightButton;
[super viewWillDisappear:animated];
}
-(IBAction)cancel
{
[[self.delegate navController] popViewControllerAnimated:YES];
}
-(IBAction)save
{
if (textFieldBeingEdited != nil)
[changedValues replaceObjectAtIndex:textFieldBeingEdited.tag withObject:textFieldBeingEdited.text];
[self.delegate valuesDidChange:[NSMutableDictionary dictionaryWithObjects:changedValues forKeys:fieldKeys]];
[[self.delegate navController] popViewControllerAnimated:YES];
}
-(void)setKeyboardType:(UIKeyboardType)theType forIndex:(NSUInteger)index
{
keyboardTypes[index] = theType;
}
#pragma mark -
- (void)setFieldNames:(NSArray *)theFieldNames
{
if ([theFieldNames count] > 5)
{
NSException *e = [NSException exceptionWithName:@"Too Many Values"
reason:@"If more than five values are provided, some will be inaccessible because of the keyboard view"
userInfo:nil];
[e raise];
}
[theFieldNames retain];
[fieldNames release];
fieldNames = theFieldNames;
}
- (void)setFieldValues:(NSArray *)theFieldValues
{
[theFieldValues retain];
[fieldValues release];
fieldValues = theFieldValues;
changedValues = [theFieldValues mutableCopy];
}
- (void)dealloc {
[fieldNames release];
[fieldKeys release];
[fieldValues release];
[textFieldBeingEdited release];
[super dealloc];
}
#pragma mark -
#pragma mark Table View Data Source Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [fieldNames count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *textFieldCellIdentifier = @"textFieldCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:textFieldCellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:textFieldCellIdentifier] autorelease];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 75, 25)];
label.textAlignment = UITextAlignmentRight;
label.tag = kDefaultLabelTag;
UIFont *font = [UIFont boldSystemFontOfSize:11];
label.textColor = [UIColor colorWithRed:0.4 green:0.4 blue:0.6 alpha:1.0];
label.font = font;
[cell.contentView addSubview:label];
[label release];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(94, 10, 200, 25)];
//textField.tag = kDefaultTextFieldTag;
textField.clearsOnBeginEditing = NO;
[textField setDelegate:self];
[textField addTarget:self
action:@selector(textFieldDone:)
forControlEvents:UIControlEventEditingDidEndOnExit];
[cell.contentView addSubview:textField];
}
UILabel *label = (UILabel *)[cell.contentView viewWithTag:kDefaultLabelTag];
UITextField *textField = nil;
for (UIView *oneView in cell.contentView.subviews)
{
if ([oneView isMemberOfClass:[UITextField class]])
textField = (UITextField *)oneView;
}
label.text = [fieldNames objectAtIndex:[indexPath row]];
textField.text = [changedValues objectAtIndex:[indexPath row]];
textField.tag = [indexPath row];
textField.keyboardType = keyboardTypes[[indexPath row]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark -
#pragma mark Text Field Delegate Methods
#pragma mark -
#pragma mark Table Delegate Methods
- (NSIndexPath *)tableView:(UITableView *)tableView
willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
return nil;
}
#pragma mark -
#pragma mark Text Field Delegate Methods
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
self.textFieldBeingEdited = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[changedValues replaceObjectAtIndex:textField.tag withObject:textField.text];
}
@end
Aucun commentaire:
Enregistrer un commentaire