It's really odd. :(
I am trying to implement swipe to delete in tableview. For this below is what I have.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"commitEditingStyle===%#", editingStyle);
if (editingStyle == UITableViewCellEditingStyleDelete) {
//add code here for when you hit delete
NSLog(#"now delete this cell");
}
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleDelete;
}
Still when I swipe, swipe is done, but I can't see Delete button.
Any idea what is going on?
Edit 1
Something more weird now.
When I say mainTableView.editing = YES; in viewDidLoad, I have below.
Why delete option is appearing on the left side?
Also with editing option, still it appear same as first image.
Edit 2
// table view delegates
- (int)numberOfSectionsInTableView:(UITableView *) tableView {
return 1;
}
- (int) tableView:(UITableView *) tableView numberOfRowsInSection:(NSInteger)section {
return actualProductsArray.count;
}
-(UITableViewCell *) tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MainCell"];
// created label and added into cell...
cell.backgroundColor = [UIColor clearColor];
cell.contentView.backgroundColor = [UIColor clearColor];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Though this is not real answer, but below was error.
While defining size of tableview, I had defined its width as 1080 against 320 and hence I was not able to see delete button as it was way ahead of screen.
I had the same problem and it wasn't related to the width of the table or not having canEditRowAtIndexPath. I noticed the right nav bar button (Edit) would flash when I swiped left. The bug I found in my code was that I was calling tableView.reloadData() inside the setEditing method.
override func setEditing(editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
tableView.reloadData()
}
When I deleted the tableView.reloadData() line, the Delete button showed up just as expected. The reason I was doing the reloadData was because in Edit mode, I added an Insert line at the bottom of the table with an editingStyleForRowAtIndexPath = .Insert
You have to try Tableview.editing=YES in ViewDidload
I am only using the below line for swipe to delete in my code it works perfectly fine for me.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source
//[self.tblinboxmsg deleteRowsAtIndexPaths:#[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
}
}
Hope it helps you too...
I think you add the label directly on cell and not on cell.contentView.
If you provide the code here
// created label and added into cell...
We can help you more.
tableView.editing = true
has the behaviour like you have on image Edit 1. (Buttons are on left side)
But the buttons are on content, which should not. Because you are adding labels on cell directly
please add the labels in contentView and try again
I know this has been solved for over a year now but for some people that might encounter this problem, This might be just a constraint issue.That is how I solved mine.
Can't believe I've been trying to solve this problem for days, literally!, because I thought it was somewhere in my code implementation because I transitioned from UITableViewController to UITableView on a UIViewController. I just copied the UITableViewCell from the original UITableViewController and the code works well from the original UITableViewController implementation.
#Fahim Parkar first screenshot is pretty much the same scenario as mine. Slide and not showing delete. I think this means that canEditRowAtIndexPath is already implemented. His answer I believed is set in code but it led me to try out to check my constraints and finally fixed it
Related
I have a UITableView and also implemented the logic to swipe to show the delete button, as such:
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
-(void)tableView:(UITableView *)tableViefw commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete {
//logic to delete...
}
}
However, I need a way for the delete button to also show up when the user clicks on a table cell. Is that possible?
I've seen other answers that suggest using [tableView setEditing: true], but that also shows the red icon on the left and I don't want that.
Thanks.
If you subclass UITabeViewCell, then you can use the didSelectRowAtIndexPath: method to get the clicked cell, you can then show a delete button (whatever design you want), and when that is clicked the cell gets deleted front the datasource and the tableView gets updated, whether there is a framework way of doing it, I do not know.
But good luck anyway :)
Try this method..
When deleting a row you must remove that data form your array. After that you need to reload tableview again to show the updated tableview
- (void)viewDidLoad
{
Your_tableview.editing=YES;
[super viewDidLoad];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(editingStyle == UITableViewCellEditingStyleDelete)
{
NSLog(#"Delete Success");
[Your_Array removeObjectAtIndex:indexPath.row];
[self.Your_tableView reloadData]
}
else
{
NSLog(#"Delete Canceled");
}
}
I'm using a UISegmentedControl to switch a UITableView between two datasets (think favorites and recents). Tapping the segmented control reloads the tableview with the different data set.
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:anim];
When the user swipes to delete a row it works fine. HOWEVER when the user switches datasets via the segmented control, the DELETED CELL gets re-used without altering it's appearance (i.e. the red 'DELETE' button is still there and the row content is nowhere to be seen). This appears to be the opposite problem that most people are seeing which is the delete button not appearing.
This is the delete code:
- (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
- (void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
if ([self.current isEqualTo:self.favorites])
{
Favorite *fav = self.favorites[indexPath.row];
NSMutableArray *mut = [self.favorites mutableCopy];
[mut removeObjectAtIndex:indexPath.row];
self.favorites = mut;
self.current = self.favorites;
[self.tableView deleteRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
}
The tableview is set to single select, and self.tableView.editing == NO. I have also tried using [self.tableView reloadData] and deleting/inserting the difference in rows from one dataset to the next. Neither works.
The UITableViewCell I'm using supplies no backgroundView or selectedBackgroundView
[EDIT]
Segmented Control Value Changed:
- (IBAction)modeChanged:(id)sender
{
if (self.listMode.selectedSegmentIndex == 1)
{
self.current = self.favorites;
}
else
{
self.current = self.recents;
}
// Tryin this:
[self.tableView reloadData];
// Tried this:
// [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
}
// Only 1 Section per table
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
return [self.current count];
}
Oh for the love of...
I wasn't calling [super prepareForReuse]; in my UITableViewCell subclass.
UGH.
I ran into the same thing: to "delete" a custom UITableViewCell, I was removing it from the table and putting it onto another list, which the user could then display in a modal view when they have regrets and want to put it back. In iOS7 (but not iOS6), the cells so moved had the big ugly "DELETE" button still on them, despite calling setEditing:NO and so on. (And in addition, the rest of the cell content was not drawn at all, even though inspecting the cells in the debugger showed that all the subpanes were still there.)
Unlike Stephen above, I hadn't overridden prepareForReuse, so that wasn't the problem. But it was related: in my case, the cells weren't created with a reuse identifier:
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
And per the docs, "If the cell object does not have an associated reuse identifier, this method is not called." But apparently, in iOS7 at least, it should be.
So the solution, in my case, was to explicitly call this [cell prepareForReuse] on each cell as I loaded it into the new table.
If you notice in the iPad contacts app when you tap on the "+" edit icon to add a new address, the cell does not expand to the left when the icon disappears (see 1st screen capture below). I am trying to do something similar but am having no luck (see 2nd screen capture below). I tried using the solution suggested here but didn't work.
For the record I am not trying to replicate the actual contacts app or integrate with contacts. We're working on something unrelated and my designer just wants to follow this pattern so doing some POC work to see what I can do.
EDIT - Another question, to verify my thinking, is that in the contacts app here what's happening is when the "+" icon is tapped, this cell is set to not editing any more, these text fields are added to the cell, the label changed, and then reloadData is called, right?
EDIT - Thanks for the suggestion Tim, I'm almost there! I had actually worked out 1/2 of it but then was running into the issue that the "+" icon was not animating out, just abruptly disappearing. So I added the reloadRows... call to commitEditingStyle but now the entire cell disappears. Here is my code:
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCellEditingStyle editingStyle = UITableViewCellEditingStyleNone;
if (self.showEditingIcon) {
editingStyle = UITableViewCellEditingStyleInsert;
self.showEditingIcon = NO;
}
return editingStyle;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
// tableView.editing = NO;
// tableView.editing = YES;
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
You can see from my commented-out lines what I had originally, which was working but as I said, was not animating - the "+" button was just abruptly disappearing. If I tried to call [tableView setEditing:NO animated:YES] it would not work. When I tried to put these calls within a UIView animation block it did not look good - could see cell temporarily shift to left and back. However now with the reload call the cell disappears completely. At the moment I'm not making any changes to my cell (for example I'm not adding text fields, etc...) because I just want to make the "+" button animating out without making the cell expand the left work on the first iteration.
Any help greatly appreciated. Thanks.
The trick is to always be in editing mode such that the cell indention remains constant. When the cell is loaded, you decide what state it is in and return the appropriate editing style, either the "insert" style or "none":
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
BOOL shouldShowInsertButton = ...;//check internal state for cell
return shouldShowInsertButton ? UITableViewCellEditingStyleInsert : UITableViewCellEditingStyleNone;
}
Then when the edit button is tapped, you update your internal state and reload the cell:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
...;//update internal state for cell
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
EDIT
Here's a working sample project.
I have the following code for a UITableView with custom cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"FolderCellViewController"];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"FolderCellViewController" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = [topLevelObjects objectAtIndex:0];
cell.editingAccessoryView=accessoryView; //accessoryView is a UIView within a UITableViewCell, and it is properly connected in IB
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
// 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 NO; //YES here makes a red delete button appear when I swipe
}
// 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
}
}
But for some when I swipe nothing happens. I haven't done anything but this-is there anything else I need to do for this to work?
EDIT: Apparently what I did only sets the editing style for when the entire table is in edit mode, not when I swipe on each individual cell. So what I want to do is when I swipe on each cell, the custom accessoryView appears for that cell. But I'm not sure how to do that..
The editing accessory view is shown when the cell enters editing mode. It does seem a little bit too hard to actually get this working, but I have managed it:
To get this to show both when entering edit mode for the whole table, and when swiping an individual row, I have implemented the following in my UITableViewController subclass:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
if (editing)
self.editingFromEditButton = YES;
[super setEditing:(BOOL)editing animated:(BOOL)animated];
self.editingFromEditButton = NO;
// Other code you may want at this point...
}
editingFromEditButton is a BOOL property of the subclass. This method is called when the standard "Edit" button is pressed. It is used in the following method which prevents the standard delete button showing:
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.editingFromEditButton)
return UITableViewCellEditingStyleNone;
// Otherwise, we are at swipe to delete
[[tableView cellForRowAtIndexPath:indexPath] setEditing:YES animated:YES];
return UITableViewCellEditingStyleNone;
}
If the whole table view is being set to editing mode then each cell will also be sent the setEditing message. If we have swiped a single row, then we need to force that cell into editing mode, and then return the UITableViewCellEditingStyleNone style to prevent the standard delete button from appearing.
Then, to dismiss the custom editing accessory, you also need the following code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Cancel the delete button if we are in swipe to edit mode
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.editing && !self.editing)
{
[cell setEditing:NO animated:YES];
return;
}
// Your standard code for when the row really is selected...
}
How do you disable selecting only a single cell in a UITableView? I have several, and I only want the last to be disabled.
To stop just some cells being selected use:
cell.userInteractionEnabled = NO;
As well as preventing selection, this also stops tableView:didSelectRowAtIndexPath: being called for the cells that have it set. It will also make voiceover treat it the same as a dimmed button (which may or may not be what you want).
Note that if you have interactive elements in the cell (ie. switches/buttons), you'll need to use cell.selectionStyle = UITableViewCellSelectionStyleNone; instead and then make sure to ignore taps on the cell in tableView:didSelectRowAtIndexPath:.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = ...
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
Throw this in your custom Table VC:
// cells lacking UITableViewCellAccessoryDisclosureIndicator will not be selectable
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType != UITableViewCellAccessoryDisclosureIndicator) {
return nil;
}
return indexPath;
}
// disabled cells will still have userinteraction enabled for their subviews
- (void)setEnabled:(BOOL)enabled forTableViewCell:(UITableViewCell *)tableViewCell
{
tableViewCell.accessoryType = (enabled) ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
// if you dont want the blue selection on tap, comment out the following line
tableViewCell.selectionStyle = (enabled) ? UITableViewCellSelectionStyleBlue : UITableViewCellSelectionStyleNone;
}
Then to enable/disable selection for someTableViewCell, do this:
[self setEnabled:state forTableViewCell:someTableViewCell];
You're done and can ship.
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self numberOfRowsInSection] == [indexPath row]) {
return nil;
} else {
return indexPath;
}
}
the last row of the table will not be selected
As I mentioned in another thread all the above methods are not solving the problem precisely. The correct way of disabling a cell is through the method
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
and in that method one has to use
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
which disables cell selection but still allows the user to interact with subviews of the cell such as a UISwitch.
The cleanest solution that I have found to this only makes use of the delegate method willDisplayCell.
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if([indexPath row] == 0) //<-----ignores touches on first cell in the UITableView
{ //simply change this around to suit your needs
cell.userInteractionEnabled = NO;
cell.textLabel.enabled = NO;
cell.detailTextLabel.enabled = NO;
}
}
You don't have to take any further action in the delegate method didSelectRowAtIndexPath to ensure that the selection of this cell is ignored. All touches on this cell will be ignored and the text in the cell will be grayed out as well.
with iOS 6.
You can use the following delegate method and return NO in case you don't it to be selected and YES in case you want it to be selected.
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
return indexPath.section == 0;
}
Try this in swift:
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
If anyone wondering how to achieve this in swift then here is my code. I am using Xcode 7 and tested using iPad Retina(iOS 9).
cell.selectionStyle = UITableViewCellSelectionStyle .None
cell.userInteractionEnabled = false
Try to place this two line code whether you want. In my case I have used this in this method for displaying cells.
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
Remember this two line code will block any kind of selection or interaction to your cells but you can only use the first line individually if you want. That is...
cell.selectionStyle = UITableViewCellSelectionStyle .None
Only this line will block the selection to your cells.
However the second line will make the cell "Read-Only". That is..
cell.userInteractionEnabled = false
Thanks
Hope this helped.