Hiding checkmarks in UITableView multiple selection during Edit Mode - ios

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.

Related

How to achieve "dequeueReusableCellWithIdentifier"

sorry, I wanna to know that apple's underlying code implementation
In storyboards you can set identifier of each of the cells you put inside the table view by setting any text to Identifier field:
The text in your code must be exactly the same, case sensitive to use it.
There are also ways of doing this programmatically to register a cell on table view before using it (setting it in viewDidLoad should be enough).
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[MyTableViewCell class] forCellReuseIdentifier:#"MyTableViewCellIdentifier"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *myCell = [tableView dequeueReusableCellWithIdentifier:#"MyTableViewCellIdentifier"];
return myCell;
}

Detect cell click in cell edit showing reordering control + disclosure control as Safari bookmarks editing

I am trying to reproduce behaviour of editing bookmarks in iOS Safari like shown here:
I managed to reproduce the look but I am struggling to detect cell click in editing mode when showing both reordering control and disclosure editing accessory type setting:
cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
Basically only the reordering and delete controls seem active, but the delegate method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
does not get called ever, how is this achieved then?
Please note I am using UITableViewController, I have implemented also:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// avoid moving "add new" row
if (indexPath.row > 0) {
return YES;
}
return NO;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return indexPath.row > 0 ? UITableViewCellEditingStyleDelete : UITableViewCellEditingStyleInsert;
}
You need to set the allowsSelectionDuringEditing to YES.
From Documentation:
A Boolean value that determines whether users can select cells while
the table view is in editing mode.
If the value of this property is YES, users can select rows during editing. The default value is NO. If you want to restrict selection of cells regardless of mode, use allowsSelection.

swipe not showing delete button

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

How to let the user reorder sections in a UITableView

I'm working on an app with stocks, arranged in portfolios. So this is a natural fit for the table view, and I'm working on the editing interaction; it's straightforward enough to allow the user to add or delete stocks, drag them around within one portfolio or to another portfolio, but one thing that I haven't been able to do gracefully is let the user drag one portfolio above or below another.
I've got a hacky solution right now, where row 0 of each section is the portfolio name, and if they drag that row above another portfolio, the whole table is reloaded with the portfolios switched. This works, but doesn't feel very natural.
I'm sure I'm not the first to encounter this problem; anyone have a more refined solution?
A related question - how do I let users create a new portfolio/section?
Easy peasy:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
{
NSMutableArray *_data;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_data = [NSMutableArray arrayWithObjects:#"One", #"Two", #"Three", nil];
self.tableView.editing = YES;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _data.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"reuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:identifier];
}
cell.textLabel.text = _data[indexPath.row];
cell.showsReorderControl = YES;
return cell;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleNone;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
[_data exchangeObjectAtIndex:sourceIndexPath.row withObjectAtIndex:destinationIndexPath.row];
}
#end
EDIT:
What you've asked for now is a little more complicated. I created an example that puts tables into cells, which gives you nested cells. The example is highly unattractive, but it works, and there's no reason you can't make it look pretty, so check it out:
https://github.com/MichaelSnowden/TableViewInCell
If that doesn't work for you, try making UITableView moveSection:(NSInteger) toSection:(NSInteger) look pretty.
Documentation for that method is here.
My experience with the above method was that it's very easy to use, and it looks nice when it's called. A smart way to use it would be to create headers with tap gesture recognizers. On the first tap, highlight that section and record that indexPath, and on the second tap, call the method on the two index paths. It should work nicely, but you won't get drag-and-drop from it.

custom editingAccessoryView not working

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...
}

Resources