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;
}
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 have a table view in which the cells are built differently depending on whether the table is editing or not. Specifically, the selection style is none when in edit mode and blue when not in edit mode.
When I transition from one to the other, I noticed that some of the cells are not updated. A quick bit of logging tells me that even though the cells' appearance changes quite drastically (accessory views are added/removed correctly for example) the table view does not refresh the selection style (nor for that matter the text).
What is going on here? Are only some attributes of the cell updated when setEditing is called? Presumably only those with a specific method allowing allocation of a separate view style (for example the EditingAccessoryType)? I guess I would benefit from a EditingSelectionStyle.
How should I resolve it? By customizing setEditing to change the selectionStyle for each cell? I'm not even sure how I would iterate through the table view to do this. reloadData isn't an option because of some animation that I am using.
I found that customizing setEditing: to iterate through the visible cells and setting the selectionStyle for each to work ok.
- (void)setEditing:(BOOL)editing animated:(BOOL)animated{
[super setEditing:editing animated:animated];
for (UITableViewCell *cell in [self.tableView visibleCells]) {
NSIndexPath *path = [self.tableView indexPathForCell:cell];
cell.selectionStyle = (self.editing && (path.row > 1 || path.section == 0)) ? UITableViewCellSelectionStyleNone : UITableViewCellSelectionStyleBlue;
}
}
If you look at the UITableViewDelegate documentation you will see a that there are five methods to customize the editing behavior. There is also the method
- (BOOL)tableView:(UITableView *)tableView
canEditRowAtIndexPath:(NSIndexPath *)indexPath
in the UITableViewDataSource documentation that will be called on each cell before you go into editing mode. The same is true for
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
that will get called for all cells that are editable. If you want to change the way the cells look you could do it in either of these. (Not implementing canEditRow.. assumes all rows are editable.)
Also note that there may be other ways to enter editing mode such as swiping on a cell, in which case
- (void)tableView:(UITableView *)tableView
willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
will be called for the cell that you swiped on:
When entering this "swipe to delete" editing mode, the table view sends a tableView:willBeginEditingRowAtIndexPath: message to the delegate to allow it to adjust its user interface.
This works on Swift 2.3, just overwriting the setEditing method in your custom cell subclass:
class MyCell: UITableViewCell {
override func setEditing(editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
//Place your code here...
}
}
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:
As is done in the iPhone Mail app, I would like have the "Delete" button which appears on swiping an editable table cell from right to left to animate when it is dismissed (by way of tapping elsewhere than the Delete button on the UITableViewCell). Instead, my Delete button immediately disappears when it is dismissed.
To invoke the Delete button on swiping a table cell in the first place, I have added (to the class which is the UITableViewDataSource and UITableViewDelegate for the UITableView in question):
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//add code here for when you hit delete
}
}
Is there something I might add to this which will handle the animation of the Delete button when it is dismissed? Thank you!
I had the same problem, just now found out that there is some problem when we have empty cell.textLabel.text. Try add in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath:
{
{...} // omitted code
cell.textLabel.text = #"whatever";
cell.textLabel.hidden = YES;
}
With this swipe button dismiss proper, but WHY?
PS: tested with custom cells and built i.n
You should not need to animate the dismissal manually, it works the same way as invoking it so not sure why it is behaving differently in your app.
Are you using custom cells by any chance? As a thought for you to try, change the shouldIndentWhileEditingRowAtIndexPath: method to return NO and see if it changes anything. The only thing I can think of is that your content indentation is interfering with the delete button area in a way that the animation can't be performed or is not behaving as it should.
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
I've just ran into this issue as well. I have a series of tableViews and I noticed that some of them have the proper dismissal fade and others don't.
It seems the difference is a UITableViewCellAccessory. If this is set to anything other than UITableViewCellAccessoryNone then you get the proper animation. I think this might be a bug. Can anyone else confirm this behavior?
**> //MARK:-Tableview delete to left in swift without any tag By using Button Action**
let point = sender.convert(CGPoint.zero, to: tableView)
guard let indexpath = tableView.indexPathForRow(at: point) else {return}
stringArr.remove(at: indexpath.row)
tableView.beginUpdates()
tableView.deleteRows(at: [IndexPath(row: indexpath.row, section: 0)], with: .left)
tableView.endUpdates()
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.