Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When moving cells in UITableView, how do I make a cell remain stationary?

I have a list of people that occupy spots. I want the user to be able to rearrange these people into different spots, however, some spots are off limits. I thought this would be most easily accomplished using UITableView's rearrangement capabilities. However, I can't figure out how to keep my unavailable spots stationary.

For example, I want to move Activia Boulanger to spot 5. The grey cells should be the immoveable cells.

The beginning view:

Beginning

What the UITableView does automatically:

What UITableView does

What I want UITableView to do:

What I want

Setting tableView:canMoveRowAtIndexPath: seems to just prevent you from being able to move a cell, but does not prevent the cell from moving in reaction to other cells' movements.

Any help would be greatly appreciated. Thanks


UPDATE: Below is some sample code with a setup for the problem. I have not included my efforts at a solution because they have all failed and would clutter things up.

#import "LDYViewController.h"

static NSString * unmoveableCellId = @"NoMove";
static NSString * moveableCellId = @"OkMove";

@implementation LDYViewController
@synthesize tableView;
@synthesize peopleList;

- (void)viewDidLoad
{
    [super viewDidLoad];

    peopleList = [[NSMutableArray alloc] initWithObjects:
                  @"Belinda Boomer", @"Activia Boulanger", @"Arnold Carter", [NSNull null], @"Attila Creighton", [NSNull null], @"Bruce Cleary", [NSNull null], nil];
    [tableView setEditing:YES];
    // Do any additional setup after loading the view, typically from a nib.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return peopleList.count;
}

- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell;

    if([peopleList objectAtIndex:indexPath.row] == [NSNull null]) {
        cell = [tableView dequeueReusableCellWithIdentifier:unmoveableCellId];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:unmoveableCellId];
            cell.userInteractionEnabled = NO;
            cell.contentView.backgroundColor = [UIColor grayColor];
        }
    } else {
        cell = [tableView dequeueReusableCellWithIdentifier:moveableCellId];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:moveableCellId];
            NSString * name = [peopleList objectAtIndex:indexPath.row];
            cell.textLabel.text = name;
        }        
    }

    return cell;
}

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

- (NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
       toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
    return proposedDestinationIndexPath;
}

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([peopleList objectAtIndex:indexPath.row] == [NSNull null]) {
        return NO;
    }

    return YES;
}    
@end
like image 219
LDY Avatar asked Apr 18 '12 02:04

LDY


2 Answers

Try this:

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath*)sourceIndexPath
       toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath

You can check the proposedDestinationIndexPath, if you don't want to move row to it, you can return the sourceIndexPath then row will be moved back, otherwise return the proposedDestinationIndexPath.

like image 112
Son Nguyen Avatar answered Nov 15 '22 08:11

Son Nguyen


Do the normal rearrange logic on your model, then when it's done, put the nulls back in where you want them. Posted code doesn't include the model, so here's a plausible model to illustrate:

// always leave our array with a null at indexes 3,5,7
// i'm sure you have better logic about where nulls go, but just to illustrate
- (void)addNulls {

    NSMutableArray *answer = [NSMutableArray array];
    for (id object in self.peopleList) {
        if (![object isKindOfClass:[NSNull self]]) {
            [answer addObject:object];
        }
    }

    assert(answer.count >= 4);
    [answer insertObject:[NSNull null] atIndex:3];
    [answer insertObject:[NSNull null] atIndex:5];
    [answer insertObject:[NSNull null] atIndex:7];
    self.peopleList = answer;
}

// build a pretend model with nulls
- (NSMutableArray *)peopleList {

    if (!_peopleList) {
        _peopleList = [NSMutableArray array];
        [_peopleList addObject:@"Moe"];
        [_peopleList addObject:@"Larry"];
        [_peopleList addObject:@"Curly"];
        [_peopleList addObject:[NSNull null]];
        [_peopleList addObject:@"Groucho"];
        [_peopleList addObject:[NSNull null]];
        [_peopleList addObject:@"Chico"];
        [_peopleList addObject:[NSNull null]];
        [_peopleList addObject:@"Harpo"];
    }
    return _peopleList;
}



// normal rearrange logic, then fix your array up
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {

    // reorder the list with the typical logic, ignoring nulls
    NSString *stringToMove = [self.peopleList objectAtIndex:fromIndexPath.row];
    [self.peopleList removeObjectAtIndex:fromIndexPath.row];
    [self.peopleList insertObject:stringToMove atIndex:toIndexPath.row];

    // now put nulls into the positions you want them
    [self addNulls];
    [self.tableView reloadData];
}
like image 30
danh Avatar answered Nov 15 '22 08:11

danh