Is it possible to make editable the UITableView by adding the commitEditingStyle method only under certain circumstances ?
I have a controller.m/.h file that is doing stuff for 3 differents storyboards viewcontrollers. I want only 2 of the 3 to be able to commitEditingStyle. I can distinguish them using the self.restorationIdentifier.
you can check tableview tag..
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableview.tag==1 || tableview.tag==2)
return UITableViewCellEditingStyleDelete;
return UITableViewCellEditingStyleNone;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
//here your code
}
}
public override UITableViewCellEditingStyle EditingStyleForRow(UITableView tableView, NSIndexPath indexPath)
{
//here we show and hide the delete for particular row
if (indexPath.Row ==1)
{
return UITableViewCellEditingStyle.Delete;
}
else {
return UITableViewCellEditingStyle.None;
}
}
public override void CommitEditingStyle(UITableView tableView, UITableViewCellEditingStyle editingStyle, NSIndexPath indexPath)
{
if (editingStyle == UITableViewCellEditingStyle.Delete)
{
//here we handle delete button action of the tableview
}
}
Well, seems that I had simply to subclass and add the commitEditingStyle on the subclass. Then change the class in the storyboard to the subclass and that's all.
Related
As default behavior, once you want to delete any single cell of table view, you will tap on delete button at left of cel, the delete confirmation button will be shown at right of cell, and then continue tapping on this button, this row will be deleted. For this behavior, you need to have 2 steps to delete a row. Is there any way can only tap on delete button(at the left of cell) to delete the cell without tapping on the confirmation button?
Do you mean deleting the row only with swapping left? Ignoring the delete button?
You could use UISwipeGestureRecognizer, like this:
class YourViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
var swipe = UISwipeGestureRecognizer(target: self, action: #selector(self.didSwipe))
self.tableView.addGestureRecognizer(swipe)
}
func didSwipe(recognizer: UIGestureRecognizer) {
if swipe.state == UIGestureRecognizerState.Ended {
let swipeLocation = swipe.locationInView(self.tableView)
if let swipedIndexPath = tableView.indexPathForRowAtPoint(swipeLocation) {
if let swipedCell = self.tableView.cellForRowAtIndexPath(swipedIndexPath) {
self.cellObjectsArray.remove(at: swipedIndexPath.row)
tableView.deleteRows(at: [swipedIndexPath], with: .fade)
}
}
}
}
}
You can delete the cell by implementing the following delegate methods, but this is a two step process,
Swipe the cell to find the delete confirmation button on right side
Click Delete (commitEditingStyle will be called)
If you want to do it in a single step/click, Add a custom button in UITableViewCell and in its selector get the indexpath of UITableViewCell and delete the object from datasource and reload table, This is similar to the code implemented in commitEditingStyle method.
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
return #"Delete";
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
//Delete the object at `indexPath` from datasource
//Update UI, by reloading section/entire table
}
Usually I get my selected cell this way:
- (void)tableView:(UITableView *)table didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = (CustomCell*) [table cellForRowAtIndexPath:indexPath];
}
But in the code I'm working with, I may have many kind of cells in my table view. How can I get the class of my selected cell (if it's for example CustomCell or CustomCell2) ?
You can check the type of cell returned
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell isKindOfClass:[CustomCell class]]) {
//do specific code
}else if([cell isKindOfClass:[CustomCell2 class]]){
//Another custom cell
}else{
//General cell
}
SWIFT 4
Just in case, if someone needed it. Get the instance of selected cell and then check it for required tableViewCell type.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = myCustomCell.cellForRow(at: indexPath)
else
{
return
}
/** MyCustomCell is your tableViewCell class for which you want to check. **/
if cell.isKind(of: MyCustomCell.self)
{
/** Do your stuff here **/
}
}
I want to block a cell to be reordered.
For example:
I have a tableview with 4 rows but don't want that the first cell can be reordered.
Is that possible?
I've tried to use:
if(indexPath.row == 0)
{
[cell setEditing:NO animated:NO];
}
But doesn't work.
Thanks.
I found the answer!
You can use the method targetIndexPathForMoveFromRowAtIndexPath from UITableViewDelegate.
-(NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath{
if (proposedDestinationIndexPath.row == 0) {
return sourceIndexPath;
}
return proposedDestinationIndexPath;
}
Your UITableViewDataSource should implement -(BOOL)tableView:canMoveRowAtIndexPath: and return NO for indexPath.row == 0
- (BOOL)tableView:canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return (indexPath.row != 0);
}
UITableViewDataSource documentation
SWIFT 5 CODE:
func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
if proposedDestinationIndexPath.row == 0 {
return sourceIndexPath
}
return proposedDestinationIndexPath
}
I have a UITableView with draggable rows and I can add/remove items. The datasource is a NSMutableArray.
Now, if I move the row with "Add new functionality" the app crashes because the dataSource is smaller since such row has not been added yet.
So I've modified this code:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row >= [dataList count]) return NO;
return YES;
}
And now I can't move it anymore. However I can still move the other rows after such row and consequently the code crashes.
How can I solve this ? Is there a way to disable the dragging "to" specific rows and not only from ?
thanks
This is exactly what the UITableViewDelegate method
-tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:
is for. Will it suit your purposes? Here's the documentation.
The previous answers and the documentation (see this and this, as mentioned in the other answers) are helpful but incomplete. I needed:
examples
to know what to do if the proposed move is not okay
Without further ado, here are some
Examples
Accept all moves
- (NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
return proposedDestinationIndexPath;
}
Reject all moves, returning the row to its initial position
- (NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
return sourceIndexPath;
}
Reject some moves, returning any rejected row to its initial position
- (NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
if (... some condition ...) {
return sourceIndexPath;
}
return proposedDestinationIndexPath;
}
How to make last row fix:
- (NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
// get number of objects
NSUInteger numberOfObjects = [[[BNRItemStore sharedStore] allItems] count];
if ( (proposedDestinationIndexPath.row+1==numberOfObjects) || (sourceIndexPath.row+1==numberOfObjects) ) {
NSLog(#"HERE");
return sourceIndexPath;
}
else{
NSLog(#"count=%d %d", [[[BNRItemStore sharedStore] allItems] count], proposedDestinationIndexPath.row);
return proposedDestinationIndexPath;
}
}
Following is the example to restrict drag and drop to 0th index of 1st section UICollectionView:
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
if session.localDragSession != nil {
// Restricts dropping to 0th index
if destinationIndexPath?.row == 0 {
return UICollectionViewDropProposal(operation: .forbidden)
}
if collectionView.hasActiveDrag {
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
} else {
return UICollectionViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)
}
}
}
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
// Prevents dragging item from 0th index
if indexPath.row == 0 {
return [UIDragItem]() // Prevents dragging item from 0th index
}
let item = self.yourArray[indexPath.row]
let itemProvider = NSItemProvider(object: item)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
Following is the working solution for disable row from moving.
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
if indexPath.row == 0{//specify your indexpath row here....
return false
}else{
return true
}
}
On my iphone app, I have a UITableView in edit mode, where user is allowed only to reorder the rows no delete permission is given.
So is there any way where I can hide "-" red button from TableView. Please let me know.
Thanks
Here is my complete solution, without indentation (0left align) of the cell!
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewCellEditingStyleNone;
}
- (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
- (BOOL)tableView:(UITableView *)tableview canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
Swift 5 equivalent to accepted answer with just the needed funcs:
extension YourViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .none
}
}
This stops indentation:
- (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
I faced a similar problem where I wanted custom checkboxes to appear in Edit mode but not the '(-)' delete button.
Stefan's answer steered me in the correct direction.
I created a toggle button and added it as an editingAccessoryView to the Cell and wired it to a method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
....
// Configure the cell...
UIButton *checkBoxButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 40.0f, 32.0f)];
[checkBoxButton setTitle:#"O" forState:UIControlStateNormal];
[checkBoxButton setTitle:#"√" forState:UIControlStateSelected];
[checkBoxButton addTarget:self action:#selector(checkBoxButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
cell.editingAccessoryType = UITableViewCellAccessoryCheckmark;
cell.editingAccessoryView = checkBoxButton;
return cell;
}
- (void)checkBoxButtonPressed:(UIButton *)sender {
sender.selected = !sender.selected;
}
Implemented these delegate methods
- (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleNone;
}
When you only want to hide the (-) dot while editing but you may want to keep the deleting functionality for the users you implement it like so in your UITableViewDelegate protocol conforming class
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.editing) return UITableViewCellEditingStyleNone;
return UITableViewCellEditingStyleDelete;
}