editable UITableView, UITextField in a cell, storing data when done is pressed
I've been banging my head on this for a day or two now and can't quite get it to work the way I want. I'm trying to mimic the address book's contact edit page (I know its been asked before).
I have a custom UITableViewCell that includes a UITextField, which sits in the same place as the detail text label, and when the edit button is pressed, they hide and unhide to show the correct items.
I'm using UITextFieldDelegate to store the info typed in the text fields into a dictionary so I can save them to the view array and my core data model when the user clicks "done".
Now the problem: If text is entered into a field, no other field/cell is selected, and done is pressed, the changed info gets ignored, it never gets stored in the dictionary.
My code right now only prints the contents of the dictionary to NSLog when done is pressed, because I don't see the point to updating the cell until the dictionary's state is correct first.
I listed out all of the UITextFieldDelegate methods with log prints when each thing gets run to try to track how things are flowing, but it didn't help me wrap my head around this specific issue.
Here's the code:
EditableCellStyle2.h
@interface EditableCellStyle2 : UITableViewCell {
CGRect editRect;
UITextField *editField;
}
@property (nonatomic, readonly, retain) UITextField *editField;
@end
EditibleCellStyle2.m
#import "EditableCellStyle2.h"
@implementation EditableCellStyle2
@synthesize editField;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code.
editRect = CGRectMake(83, 12, self.contentView.bounds.size.width-83, 19);
editField = [[UITextField alloc] initWithFrame:editRect];
editField.font = [UIFont boldSystemFontOfSize:15];
editField.textAlignment = UITextAlignmentLeft;
editField.textColor = [UIColor blackColor];
editField.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
[self.contentView addSubview:editField];
self.editField.enabled = NO;
self.editField.hidden = YES;
}
return self;
}
-(void)layoutSubviews
{
[super layoutSubviews]; // layouts the cell as UITableViewCellStyleValue2 would normally look like
editRect = CGRectMake(self.detailTextLabel.frame.origin.x, self.detailTextLabel.frame.origin.y, self.contentView.frame.size.width-self.detailTextLabel.frame.origin.x, self.detailTextLabel.frame.size.height);
editField.frame = editRect;
}
- (void)willTransitionToState:(UITableViewCellStateMask)state {
[super willTransitionToState:state];
if (state & UITableViewCellStateEditingMask) {
self.detailTextLabel.hidden = YES;
self.editField.enabled = YES;
self.editField.hidden = NO;
}
}
- (void)didTransitionToState:(UITableViewCellStateMask)state {
[super didTransitionToState:state];
if (!(state & UITableViewCellStateEditingMask)) {
self.editField.enabled = NO;
self.editField.hidden = YES;
self.detailTextLabel.hidden = NO;
self.editField.text = self.detailTextLabel.text;
}
}
- (void)dealloc {
[editField release];
[super dealloc];
}
@end
DetailViewController.h
#import <UIKit/UIKit.h>
#import "Entry.h"
#import "Station.h"
#import "EditableCellStyle2.h"
@interface EntryDetailViewController : UITableViewController <UITextFieldDelegate> {
NSManagedObjectContext *currentContext;
Entry *passedEntry;
NSMutableArray *sectionsArray;
NSMutableDictionary *editModeDict;
}
@property (nonatomic, retain) NSManagedObjectContext *currentContext;
@property (nonatomic, retain) Entry *passedEntry;
-(void)editPressed;
-(void)donePressed;
-(void)cancelPressed;
@end
DetailViewController.m
-(void)editPressed
{
[self setEditing:YES animated:YES];
}
-(void)donePressed
{
[self setEditing:NO animated:YES];
NSLog(@"%@", editModeDict);
[self.tableView reloadData];
}
-(void)cancelPressed
{
[self setEditing:NO animated:YES];
[editModeDict removeAllObjects];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return [sectionsArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
NSArray *thisSection = [sectionsArray objectAtIndex:section];
return [thisSection count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
EditableCellStyle2 *cell = (EditableCellStyle2 *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[EditableCellStyle2 alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
NSArray *array = [sectionsArray objectAtIndex:indexPath.section];
NSDictionary *dictionary = [array objectAtIndex:indexPath.row];
id key = [[dictionary allKeys] objectAtIndex:0];
cell.textLabel.text = [NSString stringWithFormat:@"%@", key];
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@", [dictionary objectForKey:key]];
// Set the edit field to match the detail label on creation so it doesn't look odd on first edit (slide down)
cell.editField.text = cell.detailTextLabel.text;
// Set the edit placeholder to match the key
cell.editField.placeholder = [NSString stringWithFormat:@"%@", key];
// Set the tag for the edit field for the cell based on what cell is being created
// We will use this in the UITextField delegate to store the data in a dictionary
if ([cell.textLabel.text isEqualToString:开发者_运维技巧@"Odometer"])
cell.editField.tag = kOdometer;
else if ([cell.textLabel.text isEqualToString:@"Quantity"])
cell.editField.tag = kQuantity;
else if ([cell.textLabel.text isEqualToString:@"PricePer"])
cell.editField.tag = kPricePer;
else if ([cell.textLabel.text isEqualToString:@"PriceTotal"])
cell.editField.tag = kPriceTotal;
else if ([cell.textLabel.text isEqualToString:@"Name"])
cell.editField.tag = kStationName;
else if ([cell.textLabel.text isEqualToString:@"Address"])
cell.editField.tag = kStationAddress;
else if ([cell.textLabel.text isEqualToString:@"City"])
cell.editField.tag = kStationCity;
else if ([cell.textLabel.text isEqualToString:@"State"])
cell.editField.tag = kStationState;
else if ([cell.textLabel.text isEqualToString:@"Zip"])
cell.editField.tag = kStationZip;
else if ([cell.textLabel.text isEqualToString:@"Notes"])
cell.editField.tag = kNotes;
// Set the delegate of the edit field to self
[cell.editField setDelegate:self];
return cell;
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
// When we go into editing mode, hide the back button, when we come out of editing mode, show it.
self.navigationItem.hidesBackButton = editing;
// Replace the back button with a cancel button that is only active while in edit mode
if (editing) {
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelPressed)];
self.navigationItem.leftBarButtonItem = cancelButton;
[cancelButton release];
// clear the right bar button (edit)
self.navigationItem.rightBarButtonItem = nil;
// make the right bar button a done button
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(donePressed)];
self.navigationItem.rightBarButtonItem = doneButton;
[doneButton release];
}
else {
// clear out our cancel button
self.navigationItem.leftBarButtonItem = nil;
// clear out the right bar button (done)
self.navigationItem.rightBarButtonItem = nil;
// make the right bar button an edit button
UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(editPressed)];
self.navigationItem.rightBarButtonItem = editButton;
[editButton release];
}
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleNone;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
switch (textField.tag) {
case kOdometer:
[editModeDict setValue:textField.text forKey:@"Odometer"];
break;
case kQuantity:
[editModeDict setValue:textField.text forKey:@"Quantity"];
break;
case kPricePer:
[editModeDict setValue:textField.text forKey:@"PricePer"];
break;
case kPriceTotal:
[editModeDict setValue:textField.text forKey:@"PriceTotal"];
break;
case kStationName:
[editModeDict setValue:textField.text forKey:@"Name"];
break;
case kStationAddress:
[editModeDict setValue:textField.text forKey:@"Address"];
break;
case kStationCity:
[editModeDict setValue:textField.text forKey:@"City"];
break;
case kStationState:
[editModeDict setValue:textField.text forKey:@"State"];
break;
case kStationZip:
[editModeDict setValue:textField.text forKey:@"Zip"];
break;
case kNotes:
[editModeDict setValue:textField.text forKey:@"Notes"];
break;
default:
break;
}
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
sectionsArray = nil;
}
- (void)dealloc {
[sectionsArray release];
[editModeDict release];
[currentContext release];
[passedEntry release];
[super dealloc];
}
@end
Try this:
create a method
-(NSString *)getInEditTextFieldValue
{
if([myTextField isFirstResponder])
{
// get the text of myTextField and set it to text.
return myTextField.text;
}
else
{
return nil;
}
}
and in your donePressed:
-(void)donePressed
{
NSString* myText = [self getInEditTextFieldValue];
if(myText != nil)
{
// add myText to your dictionary
}
// save logic goes here...
// reload data for table view...
}
I'm not with my mac now so I cannot try the code, but the logic defiantly worked for me. Your UITextFieldDelegate methods should pick up the values of all text fields you have except the one that's the first responder. What you have to do is a little bit more work to check and get the value.
Hope this can help you.
You need to reference your textfield properly in UITableCell
first. Then on click of done button method you can also get the cell object. Based on contentView
of your type object (in your case of type UITextField
) can be obtained & you can get the text from it. That way you can update your database for all fields.
Your doneButton() gets called before textFieldShouldEndEditing. Try to change responder and you will see that one being active in time of doneButton click will not save its data.
精彩评论