I am working on an iOS app that uses a very common Core Data based tableview to display items and when one it selected, it shows a more detailed view, much like the Contacts app. The detail view itself is a programmatically generated grouped table with a custom (nib-defined) view for a header that has a picture and a name. Some of the cells in the table are custom cells that have a label name and a textbox value. In "edit" mode, the editable table cells (and the name in the header) have .clearButtonMode set to UITextFieldViewModeAlways to show that they are editable.
I am currently using the same view controller to display the detailed information, edit the information, and add a new record to the original list.
When a new item is being added, the view controller is created modally with a custom init overload that sets a flag in the view controller to indicate that it is adding the record. This allows it to start in edit mode and if edit mode is left, the model view is dropped away. The right menubar button is the usual Edit/Done, and the left one is a cancel button. When an existing item is being edited, the left button (normal back button) is replaced with a cancel button.
I am starting to have second thoughts as 开发者_开发问答to whether or not having one view controller handle three different modes is the way to go. There are few issues that I am not sure how to handle.
1) How do I tell if edit mode is left by hitting "Done"? Is there an action for it? If cancel is hit, the action either dismisses itself (add mode) or restores the previous values leaves edit mode. I suppose I could put a check in my setEditing override to handle it, but it seems that there should be a better way.
2) When edit mode is entered and I set the editable text fields to UITextFieldViewModeAlways, is there a way to animate the appearance of the 'X' buttons so that they fade in with the editing indicators on the regular cells?
Are there easy solutions to these problems or is my 3-in-1 view controller a bad idea? It doesn't seem right to remake the same view for different modes, but having multiple modes for a view controller seems to be a bit of a hassle.
jorj
I like the 3-in-1 approach and use it all the time. There are lots of advantages: one xib, one view controller, one simple protocol between the list and detail view controllers. Yes, there are a few more checks like if (self.editing) ...
but I like that better than more view controllers and xibs.
To help with adding I expose a BOOL that the delegate can set.
@property (nonatomic) BOOL adding;
1) The built-in editButtonItem does not allow you to intercept it before setEditing:animated: This is problematic when you are doing data validation after Done is tapped. For that reason I rarely use editButtonItem and use my own Edit, Done, and Cancel buttons with their own action methods. See below.
2) For this I like UITableView's reloadSections:withRowAnimation. It might work in your case.
- (void)edit:(id)sender
{
self.editing = YES;
}
- (void)done:(id)sender
{
// data validation here
if (everythingChecksOut)
{
//save here
} else {
return; //something didn't validate
}
//if control reaches here all is good
//let the delegate know what happened...
if (self.adding) {
[self.delegate didFinishAddingWithData:self.yourData];
} else {
[self.delegate didFinishEditingWithData:self.yourData];
}
self.adding = NO;
self.editing = NO;
}
- (void)cancel:(id)sender
{
[self.view endEditing:YES]; //in theory, forces the view that is editing to resign first responder
//in practise I find it doesn't work with the YES parameter and I have to use my own flag
// roll back any changes here
self.editing = NO;
if (self.adding) //let the delegate know we cancelled the add...
{
[self.delegate didCancelAdd];
}
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
//set your nav bar title
[self.tableview.editing = editing]; //you may or may not require this
[self.tableview reloadSections... withRowAnimation:yourChoice];
if (editing)
{
//install your Done and Cancel buttons
} else {
//remove Cancel and put the Edit button back
}
}
Then in viewDidLoad...
- (void)viewDidLoad
{
[super viewDidLoad];
//whatever else you do
if (self.adding)
{
self.editing = YES;
}
}
I haven't fully understood the questions you have raised, but here are some thoughts on structure which are probably more useful in the first instance...
It seems you are doing too much with a single UITableViewController and inevitably you will end up with lots of if statements and confusing code. I'd break it down into two separate UITableViewControllers, one to handle the main view (and any subsequent editing mode you require) and then another to handle the detail view. Either or both of these could then use nibs as you require.
Using two controllers like this will allow you to simply push the second detailViewController onto a navigation stack, rather than presenting it modally which doesn't seem like the obvious thing to do in this instance.
However, if you would prefer it to be presented modally, you could write a protocol for the detailView which sends messages in the event of 'Cancel', 'Edit' or 'Done' buttons being pushed. The first viewController could then implement the protocol and receive these events.
I hope that helps...
精彩评论