Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS - Allow default row movement in `UITableView` without editing mode

I want to allow the default row movement in a UITableView without it being in editing mode, and without compromising the default behaviour of the UITableView.

movable cell

The image above displays a cell in editing mode, with movement enabled.

I tried simply running for (UIView *subview in cell.subviews) (while my UITableView was in editing mode), but the button didn't turn up:

<UITableViewCellScrollView: 0x8cabd80; frame = (0 0; 320 44); autoresize = W+H; gestureRecognizers = <NSArray: 0x8c9ba20>; layer = <CALayer: 0x8ca14b0>; contentOffset: {0, 0}>

How can allow/add the movement "button" without enabling editing mode in my UITableView?

Creating and adding a UIButton with the default function for movement is also an option.

like image 213
Aleksander Azizi Avatar asked Apr 03 '14 21:04

Aleksander Azizi


People also ask

Which method is used to allow moving of row in Uitableview?

And you can use the tableview's editing property to distinguish how the cell should look like in your tableView:cellForRowAtIndexPath: method. So even turning off the move-functionality is easier by setting your tableview back to editing = NO , the move-icon would disappear and the accessoryType symbol shows up again.

What is tableview in iOS?

Overview. Table views in iOS display rows of vertically scrolling content in a single column. Each row in the table contains one piece of your app's content. For example, the Contacts app displays the name of each contact in a separate row, and the main page of the Settings app displays the available groups of settings ...

How tableview works?

To use the tableview, we need to set its delegate and data source properties. The tableview is a data-driven object, i.e., it gets the data to be shown from the data source object. In the real-world applications, the data source object contains the data which is returned by an API call from the database server.


2 Answers

I actually do something similar for one of my apps. It uses the delegate methods for table editing and a bit of 'tricking' the user. 100% built-in Apple functionality.

1 - Set the table to editing (I do it in viewWillAppear)

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self.tableView setEditing:YES];
}

2 - Hide the default accessory icon:

-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView 
        editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
        //remove any editing accessories (AKA) delete button 
        return UITableViewCellAccessoryNone;
       }

3 - Keep editing mode from moving everything to the right (in the cell)

 -(BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath{
return NO;
}

4 - At this point you should be able to drag the cells around without it looking like it is in editing mode. Here we trick the user. Create your own "move" icon (three lines in the default case, whatever icon you want in your case) and add the imageView right where it would normally go on the cell.

5 - Finally, implement the delegate method to actually rearrange your underlying datasource.

-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{

    //Get original id
    NSMutableArray *originalArray = [self.model.items objectAtIndex:sourceIndexPath.section];
    Item * original = [originalArray objectAtIndex:sourceIndexPath.row];

    //Get destination id
    NSMutableArray *destinationArray = [self.model.items objectAtIndex:destinationIndexPath.section];
    Item * destination = [destinationArray objectAtIndex:destinationIndexPath.row];

    CGPoint temp = CGPointMake([original.section intValue], [original.row intValue]);

    original.row = destination.row;
    original.section = destination.section;

    destination.section = @(temp.x);
    destination.row = @(temp.y);

    //Put destination value in original array
    [originalArray replaceObjectAtIndex:sourceIndexPath.row withObject:destination];

    //put original value in destination array
    [destinationArray replaceObjectAtIndex:destinationIndexPath.row withObject:original];

    //reload tableview smoothly to reflect changes
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIView transitionWithView:tableView duration:duration options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
            [tableView reloadData];
        } completion:NULL];
    });
 }
like image 137
William Falcon Avatar answered Oct 12 '22 03:10

William Falcon


William Falcon's answer in swift 3

1 - Set the table to editing (I do it in viewWillAppear)

override func viewWillAppear(_ animated: Bool) {
   super.viewWillAppear(animated: animated)
   tableView.setEditing(true, animated: false)
}

2 - Hide the default accessory icon:

override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
    return .none
}

3 - Keep editing mode from moving everything to the right (in the cell)

override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
    return false
}

4 - Not required in swift 3

5 - Reorder your array

Extra Note

If you want to have your table cells selectable, add the following code within viewWillAppear() function.

tableView.allowsSelectionDuringEditing = true
like image 32
James Parker Avatar answered Oct 12 '22 05:10

James Parker