I have refered "Managing the reordering of rows" in "UITableView Programming Guide".
I have written the same code for my application for rearranging the rows of tableView but not able to rearrange the rows in tableView. The delegates "canMoveRowAtIndex" and "moveRowAtIndex" have not been called though I set tableView in editing mode through "setEditing:animated".I dont want to use core data for implementing this.
Can u provide the detailed code for this?? (I would like rearrange the rows of tableView as we do for icons by long press and then moving them)
Are you sure to add properly the "Edit" button ?
On my code (withoutcoredata), with a navigation controller, I have:
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animate
{
[super setEditing:editing animated:animate];
[self.navigationItem setHidesBackButton:editing animated:YES];
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
//...
}
If the methods aren't being called, chances are you either haven't set the table view instance's delegate outlet to point to your controller, or you've spelled the names of the delegate methods incorrectly.
One trick to help avoid misspellings is to go to the header file where the methods are declared (in this case, UITableViewController.h) copy the method declaration(s), and paste them into your source file. Otherwise, I try to use Xcode's completion mechanism to ensure that I don't accidentally misspell things.
Related
If you have used Messages application in iOS, you know how we could invoke UITableViewCellAccessoryCheckmark in any message through edit button and then select each bubble/cell for forward or deletion purpose.
I'm trying to do the same in my application. I can tap on edit and UITableViewCellAcessoryCheckMark is shown, but I can't select the cells using it. What more do I need to implement?
Any help would be appreciated. Here is the code -
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellAccessoryCheckmark;
}
For a table view as shown in the picture, where one or more cells can be selected with a checkmark symbol, you have to set allowsMultipleSelectionDuringEditing = YES on the table view. This can be done either in viewDidLoad with
self.tableView.allowsMultipleSelectionDuringEditing = YES
or in the Attributes Inspector of the table view in the NIB/Storyboard file by setting "Editing" to "Multiple Selection During Editing".
The tableView:editingStyleForRowAtIndexPath: method is not needed for this.
(And btw your method returns UITableViewCellAccessoryCheckmark which is a UITableViewCellAccessoryType and not a UITableViewCellEditingStyle.)
I know, that when I implement tableView:willBeginEditingRowAtIndexPath:and tableView:didEndEditingRowAtIndexPath:, a swipe-to-delete does not call setEditing:animated: at my UITableViewController (being the delegate of the UITableView).
I have a custom UITableViewCell implementation that does a little UI rearrangements when going to edit mode. I wanted to be smart and implemented these changes in setEditing:animated: at the table view cell implementation itself (which obviously makes sense).
However, when swiping to delete, I still get a call to setEditing:animated: at my table view cell implementation. And I have no parameter that tells me that I am swiping. The call stack also shows none of my own methods that would give me a chance to do something. It shows that setEditing:animated is called at the UITableView. The only thing obviously is, that it is not called at the delegate (my controller in this case).
Of course, I could set a flag at the cell in tableView:willBeginEditingRowAtIndexPath: that tells it that the next setEditing call will be for a swipe, but that does not sound like good style.
Edit: it doesn't even work, because it is not guaranteed that tableView:didEndEditingRowAtIndexPath: is called, so I cannot set the flag back.
Any ideas how to solve this issue elegantly?
I think UITableViewCell's willTransitionToState: instance method may be what you are looking for. Something like this:
- (void)willTransitionToState:(UITableViewCellStateMask)state
{
if (state == UITableViewCellStateShowingDeleteConfirmationMask) {
swipedToDelete = YES; // BOOL ivar
}
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
if (swipedToDelete) {
// do your stuff, or don't
}
}
Is that it?
I know this has probably been done to death, but the solutions presented didn't seem to be a complete simple answer, nor did they seem to provide good example code, so I thought I'd add my answer.
Add to your class a private instance variable:
#implementation MyTableViewController {
BOOL _cellSwiped;
}
Override the setEditing method to look for the _cellSwiped variable and only propagate if we didn't swipe. The part that people seem to be missing is that _cellSwiped needs to be reset back to NO otherwise you will never be able to use the edit button after swiping!
- (void) setEditing:(BOOL)editing animated:(BOOL)animated {
if (!_cellSwiped) {
[super setEditing:editing animated:animated];
} else if (!editing) {
_cellSwiped = NO;
}
}
Finally, add this method override to detect the swipe:
- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath {
_cellSwiped = YES;
}
What I do is something like this:
- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
cellSwiped = YES;
self.editing = NO;
}
Then in the
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
method I simply check to see if the cellSwiped ivar is set and modify the UI accordingly.
This is an old question, but I'm wondering why nobody seems to be aware of the fact that there is a showingDeleteConfirmation property built right into UITableViewCell (since iOS 2.0):
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
BOOL reallyEditing = editing && !self.showingDeleteConfirmation;
// [...]
}
No need to override -willTransitionToState: and manually keep track of the state.
- (void)tableView:(UITableView *)tableview commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if(editingStyle != UITableViewCellEditingStyleDelete) {
// add code here
}
}
When called, this method will perform the following operations
UITableViewCellEditingStyleNone,
UITableViewCellEditingStyleDelete,
UITableViewCellEditingStyleInsert
If you don't want the swipe option you can set the bool variable in the delegate method
- (void)willTransitionToState:(UITableViewCellStateMask)state
willTransitionToState will be called before
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:
I have a core data/ uitableview based app. Actually 80% of the code so far is equal to the Apple Sample app CoreDataRecipes. My problem is that when I enter the edit mode (by pushing the edit button), there are no "delete badges" on the left side of the rows. Bumper.
The differences in code with CoreDataRecipes:
I have custom UITabelview cell with
a nib file instead of code only.
My Tableview is an Outlet inside my class view. So my class
RecipeListTableViewController is an
UIViewController with Tableview delegates instead of a UITableViewController
What I tried:
The Tableview works fine. There are no linking or delegate issues
I checked if the table actually
enters the edit mode. It does. You
can see that because the "Add" button
is disabled.
I checked if the editingstyle is ok. It should be by default but to make sure I added:
(UITableViewCellEditingStyle)tableView:(UITableView*)tableVieweditingStyleForRowAtIndexPath(NSIndexPath*)indexPath {return UITableViewCellEditingStyleDelete;}
I checked if the delete icons where not behind my cellview. There are not. I now think that the cell behaviour of moving to the right is handled by iOS.
When I swipe the cell, the right delete button appears and works as it should
I tried to build the behaviour my self with a layoutSubviews. Nothing changed when entering the edit mode. But when I swipe, now I see my subview in one row:
Anyone any ideas? It must be something simple.
Make sure that
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
If this is not set to return YES then the badges will not be enabled. The default is set to return NO
I think you have not added the line
tableView.editing=YES on clicking the Edit button
Try by setting it!
Since yours is a UIViewController, the tableview doesnt get the setEditing call. Just add:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self.tv setEditing:editing animated:YES];
}
Make sure you have setup the outlet/ delegate/ datasource
then these:
-(void)editButtonTapped
{
[self.tableView setEditing:YES animated:YES];
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
I read the documentation about how to manage deletion and reordering of rows in a UITableView. I created the edit button and I'm able to delete rows. I would like the user to be able to reorder the rows as well. It seems simple, but I can't understand how to tell the cells that they can be moved.
To tell the rows they can be deleted I use the editingStyleForRowAtIndexPath, but how do I tell the cell it can also be moved and where do I set the showsReorderControl? I tried to place in cellForRowAtIndexPath, but nothing is shown.
Thanks!
You have to say that rows can be moved:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
and implement this delegate to update your data source:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
See Managing the Reordering of Rows of Table View Programming Guide for iOS
In my case I have implemented all the required UITableViewDelegate methods as mentioned in the Apple document and in the answers here, but still cannot see the reorder control. Eventually I found out it's because I overrode the layoutSubviews method without calling the super's default implementation. After I added the [super layoutSubviews], my reorder control finally appears.
The reason why we need to call [super layoutSubviews] is because when we toggle the table's editing property it would call the cell's layoutSubviews method, and the system provided controls such as the reorder control is displayed within UITableViewCell's default layoutSubviews method. Once you realize this you can also modify your layoutSubviews implementation to change the appearance of your cell depending on whether it is being edited or not to make it less clumsy when the reorder control appears.
So here is a checklist for the row reordering:
make sure the delegate methods tableView:canMoveRowAtIndexPath and tableView:moveRowAtIndexPath:toIndexPath are implemented
make sure the tableView's editing property is set to YES
If you have a custom UITableViewCell, make sure you call
[super layoutSubviews] if you override this method
Adding to #benoit answer above. If your model happens to be a mutable array, something like this would suffice for the tableView:moveRowAtIndexPath:toIndexPath:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
id objectToMove = [_objects objectAtIndex:fromIndexPath.row];
[_objects removeObjectAtIndex:fromIndexPath.row];
[_objects insertObject:objectToMove atIndex:toIndexPath.row];
[tableView reloadData];
[self saveObjects]; // A method of your own to make new positions persistent
}
try this . . .this will handle arranging and updating of cell in case of simple tableview
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
[tableData insertObject: [tableData objectAtIndex:sourceIndexPath.row] atIndex:destinationIndexPath.row];
[tableData removeObjectAtIndex:(sourceIndexPath.row + 1)];
}
yesterday I just asked following question.
How to customize tableView Section View - iPhone
I found some new method.
Even in apple documentation I didn't found this method.
Is it some thing like hidden methods?
Does anybody provides all methods listing?
Including sample code.
Say for example.
UITableView methods
Whenever I insert tableView in my view Controller.
I have to either type or copy from some where.
If I want to include picker I have to find out UIPicker methods,
sameway
Alertview, ActionSheet, Tab Bar Controller all has different methods.
Isn't it possible, like if we include A tableView in our ViewController, Automatically all tableview methods are added to .m file.
(For example, A navigation based application has all tableView methods in rootview controller by default)
Let Me Clarify Again,
"I need proper source where all methods (like rootview controller has almost all table methods) "
So, when ever I want to add any control I just copy the code & add to my Project.
The reason Behind this
"We can target on the work instead of finding proper methods & typing them."
See, Suppose If I add a Table View to my View Controller, I must have the methods like ..didSelectAtRow..,..CellForRow...,etc.
So, after adding tableView - for managing table view I have to go for finding methods & type them in my .m file.
Suppose, I add tableView. All methods should be added to my .m file as given below.
<pre>
pragma mark Table view methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
return cell;
}
// Override to support row selection in the table view.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here -- for example, create and push another view controller.
// AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:#"AnotherView" bundle:nil];
// [self.navigationController pushViewController:anotherViewController animated:YES];
// [anotherViewController release];
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source.
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the item to be re-orderable.
return YES;
}
I provided the answer to the question you mentioned - it definitely is in the Apple documentation (although as you say, not in the sample file). Remember the method name is
tableview:didSelectRowAtIndexPath
if you miss off the "tableview:" bit at the beginning and just search for
didSelectRowAtIndexPath
you won't find it in the documentation so easily.
If you look in the documentation that comes with XCode, you will see, for example, all methods that you can implement for the UITableview Delegate, including the one I posted to your previous answer. Just type "UITableview" into XCode help, and then select "UITableview delegate". It will then display all the methods available for you to call, and you can even just copy and paste them straight into your code.
I don't know if anyone's already done this and made the "template" classes you ask about available, but it should be very easy for you to do this yourself if you want.
Hope that helps
Sure; implementors of classes are free to implement any number of methods as a part of a class's internal implementation.
But that doesn't mean that you should use them.
You can use the Objective-C runtime's API for figuring out all the methods and classes, including those that aren't publicly declared.
But don't bother.
Specifically, if a method is not declared in the provided header files and is not documented in the documentation, don't use it. Using such a method will lead to fragility and maintenance headaches; your app may likely break at the next software update.
On the iPhone, your are expressly directed not to use private interfaces and your app will run the risk of rejection if you do so.
But I don't think that is what you are really asking. You mention:
Say for example. UITableView methods
includes
didSelectRowAtIndexPath
cellForRowAtIndex Path
numberOfSectionsInTableView
titleForHeaderInSection
However, UITableView does not declare any of those methods. Instead, it declares:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
Or, succinctly, tableView:didSelectRowAtIndexPath:, etc...
The methods you describe are in the documentation. They're in UITableViewDelegate and UITableViewDataSource, which are described at the top of the UITableView documentation. You can easily copy and paste the method definitions you need from the documentation. You can also find the protocol definition in the headers easily by using "File>Open Quickly..." and typing in the name of the protocol ("UITableViewDelegate" for instance). They are often written in the headers to make it easy to copy and paste what you need most often.
This is sometimes a small hassle in Cocoa, because Xcode doesn't auto-complete method signatures. It would save a little trouble if it did. But the solution is not to implement every delegate method that exists (as #bbum pointed out earlier). In the vast majority of cases, only a small fraction of the possible delegate methods are ever implemented. So automatically populating them all would cause much more work than it saved.