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...
}
Related
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
I've got a UITableView which is automatically set up for multiple selection in Edit Mode using the following lines in viewDidLoad:
self.tableView.allowsMultipleSelectionDuringEditing = YES;
[self setEditing:YES animated:YES];
However, I'd like to indicate that a row was selected by changing its background color, rather than by the checkmarks which automatically appear along the left of each row. (For example, the ones that appear when editing the email list in the Mail app, or being discussed in this SO question.) I've got it working for the most part, except that I can't get those checkboxes, which are automatically created as part of putting the UITableView into Edit Mode, to go away.
Below is the code I'm working with:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _Hierachy.cellCount;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *testCell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(testCell == nil) {
testCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
[[testCell textLabel] setText:#"Test Cell"];
return testCell;
}
Those are the only UITableView methods I've got so far, so everything else should be default behavior.
Does anyone know how to hide those checkmarks along the left, in Edit Mode? I've seen many questions about checkmarks in the accessory portion of the cell, but as I understand it, this is a different thing. I've also seen people talk about the tableView:didSelectRowAtIndexPath: method, but these checkmarks are created when the table enters Edit mode and dismissed when the user taps "Done," so that method doesn't seem related.
The closest I've come is finding this method:
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath{
return NO;
}
But that just prevents the cell's content from indenting to make room for the checkmarks. The checkmarks still appear.
Surely there's a way to hide those checkmarks, and still allow multiple selection in Edit Mode? Or are those checkmarks seriously mandatory behavior for a UITableView in Edit Mode with Multiple Selection enabled?
EDIT: I am (reluctantly) open to answers that are somewhat hack-y, like moving the frame of the checkmarks until it's off the screen. This app is for internal use, and won't need to be approved for the App Store. But given that the checkmarks are created automatically when the UITableView moves into Edit Mode, I don't even know how to get them as objects to alter. Any help would be appreciated!
You'll have to subclass your UITableViewCell and override the (void)setEditing:animated: method like this:
#import "MyCustomCell.h"
#implementation MyCustomCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)setSelectedBackgroundView:(UIView *)selectedBackgroundView
{
//Cell Selected Color: CLEAR
[super setSelectedBackgroundView:selectedBackgroundView];
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
//Cell Edit Mode NO Indent & Selected Color: CLEAR
[super setEditing:NO animated:animated];
[self setNeedsLayout];
}
#end
After you do that, go to Inteface Builder and make your cell part of the class MyCustomCell.
After you make your cell part of MyCustomCell class in IB, import MyCustomCell.h in your UITableViewController and modify the following in your code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCell *testCell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(testCell == nil) {
testCell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
[[testCell textLabel] setText:#"Test Cell"];
return testCell;
}
UPDATE:
You could also do the following in your TableView's tableView:editingStyleForRowAtIndexPath:
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleNone;
}
But you will get your cell indented. To remove that indent you'll have to subclass the Cell.
You should be good to go after doing this! I've just tested it and it works the way you want it!
Here is the most simple solution for multiple selection with no checkmarks:
- (BOOL)tableView:(UITableView*)tableView canEditRowAtIndexPath:(NSIndexPath*)indexPath {
return NO;
}
This will cause the cells to be selected using the default selection style (gray or using your custom selection background), and no checkmarks will appear.
A word on whatever solution you pick. Users expect a consistent experience across multiple applications, and these checkmarks are part of this consistency. Make sure to have a good reason to change a normal OS look and feel.
here is how to achieve:
swipe to delete works
you don't see the checkbox, delete item or anything else on the left of the cell when in editing mode
Cell indentation still works normally (you can turn this off if you want)
(bonus) Support multiple selection
so - in your UITableViewDelegate
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.isEditing)
{
return UITableViewCellEditingStyleNone;
}
else
{
return UITableViewCellEditingStyleDelete;
}
}
- (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
(do stuff)
}
you also need to configure your UITableView
self.table.allowsMultipleSelectionDuringEditing=NO;
now if you actually do want multiple selection;
self.table.allowsSelectionDuringEditing=YES;
then manage the selected cells yourself.
I put a custom checkbox in my UITableViewCell subclass, and I also change the value in response to
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
The questioner wants to indicate selection with the background colour - that part should be straightforward.
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.
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.