开发者

How can I refresh a UITableView while a user is re-arranging cells?

开发者 https://www.devze.com 2023-04-01 20:56 出处:网络
I have an editable UITableView. While my user is re-arranging the cells, I want to be able to update the tableview because I get a funny situation when I re-arrange the bottom cell and insert it into

I have an editable UITableView. While my user is re-arranging the cells, I want to be able to update the tableview because I get a funny situation when I re-arrange the bottom cell and insert it into the middle. It create a开发者_高级运维n unwanted effect because the bottom row is rounded and the middle row should not be. How can I prevent this from happening?

How can I refresh a UITableView while a user is re-arranging cells?

To achieve this look I had to set the backgroundView of each UITableViewCell. The top and bottom ones are using a separate image than ones in the middle.

UPDATED:

I am not sure if I am missing any cases, because the images still get messed up when re-ordering.

for (NSIndexPath* visibleIndexPath in tableView.indexPathsForVisibleRows) {
        UITableViewCell* cell = [tableView cellForRowAtIndexPath:visibleIndexPath];

        //Top moving to middle rows
        if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row != sectionRows - 1) {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablemiddle55@2x.png"];
        }
        //Top moving to bottom
        else if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row == sectionRows - 1) {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablebottom55@2x.png"];
        }
        //Top moving to top
        else if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row == 0) {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tabletop55@2x.png"];
        }
        //Middle moving to top
        else if (sourceIndexPath.row != 0 && sourceIndexPath.row != sectionRows -1 && proposedDestinationIndexPath.row == 0)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tabletop55@2x.png"];
        }
        //Middle moving to bottom
        else if (sourceIndexPath.row != 0 && sourceIndexPath.row != sectionRows -1 && proposedDestinationIndexPath.row == sectionRows - 1)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablebottom55@2x.png"];
        }
        //Middle moving to middle
        else if (sourceIndexPath.row != 0 && sourceIndexPath.row != sectionRows -1 && 
                 proposedDestinationIndexPath.row != sectionRows -1 && proposedDestinationIndexPath.row !=0)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablemiddle55@2x.png"];
        }
        //Bottom moving to top
        else if (sourceIndexPath.row == sectionRows - 1 && proposedDestinationIndexPath.row == 0)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tabletop@2x.png"];
        }
        //Bottom moving to middle
        else if (sourceIndexPath.row == sectionRows - 1 && proposedDestinationIndexPath.row != 0 && proposedDestinationIndexPath.row != sectionRows - 1)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablemiddle@2x.png"];
        }
        //Bottom moving to bottom
        else if (sourceIndexPath.row == sectionRows - 1 && proposedDestinationIndexPath.row == sectionRows - 1)
        {
            ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablebottom@2x.png"];
        }
    }


Well, you simply need to change the background views of the cells that changed just like you did in tableview:cellForRowAtIndexPath:.

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
   //The rest of your stuff you need to do

   for (NSIndexPath* visibleIndexPath in self.tableView.indexPathsForVisibleRows) {
       UITableViewCell* visibleCell [self.tableView cellForRowAtIndexPath:visibleIndexPath];
       if (visibleIndexPath.row == 0) ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tabletop55.png"];
       else if (visibleIndexPath.row == [self tableView:tableView numberOfRowsInSection:visibleIndexPath.section) {
           ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablebottom55.png"];
       }
       else ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablemiddile55.png"];
   }
}


The code you posted is mostly wrong because of the for {}. As it stands right now, you do something like "if the destination is such and the source is such, modify all the currently visible cells". But anyway, this is not the main problem.

I must say, I've played a lot of time with the method tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: before even attempting to answer this question. Now I feel more confident to write it.

For starters, using this method in conjunction with tableView:cellForRowAtIndexPath: is not a good choice if you don't know what's happening. Simply put, even though the cells have shifted for the animation, the changes don't really affect the tableView until the user stops dragging the cell.

For example, let's say that you have the cell at index 0 with the title @"Hello", and the next cell with @"World", if you start dragging the first cell downwards, the animation will move the cell "Hello" one row upwards, but calling tableView:cellForRowAtIndexPath for the row at index 0 will always return the "Hello" cell. The tableView is unaffected until the tableView reorder ends, everything else is just eye-candy.

So, to answer your question, and to swap the images on the fly (as soon as the user moves the cell), you should do the following, for example, for the first row:

//Top moving to middle rows
if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row != 0)
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:sourceIndexPath.section]];
    ((UIImageView *)cell.backgroundView).image = [UIImage imageNamed:@"tablemiddle55"];
}

One the user drags the row 0 downwards, it tells the row at 1 to swap its background to the top, as he will become the new top row. Similar cases must be considered for the bottom row, or middle row becoming the first one. Also, the for {} with the visible cells is not necessary in this case.

Edit: Okay, I managed to make ALL the cases, it has some weird things here and there, but it works most of the time. The code here just changes the detailLabel to "First"/"Middle"/"Last", but that should be easy to change with a Find&Replace.

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    //NSLog(@"%d -> %d (proposed)", sourceIndexPath.row, proposedDestinationIndexPath.row);

    NSInteger lastRow = [arrayWithContent count]-1;

    // Adjust the row being moved
    if (proposedDestinationIndexPath.row == 0)
        [tableView cellForRowAtIndexPath:sourceIndexPath].detailTextLabel.text = @"First";
    else if (proposedDestinationIndexPath.row == lastRow)
        [tableView cellForRowAtIndexPath:sourceIndexPath].detailTextLabel.text = @"Last";
    else
        [tableView cellForRowAtIndexPath:sourceIndexPath].detailTextLabel.text = @"Middle";

    // Top -> Middle
    if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row == 1)
    {
        NSLog(@"Top -> Middle");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]].detailTextLabel.text = @"First";
    }
    // Top -> Top (user is screwing around)
    else if (sourceIndexPath.row == 0 && proposedDestinationIndexPath.row == 0)
    {
        NSLog(@"Top -> Top");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]].detailTextLabel.text = @"Middle";
    }
    // Middle -> Top
    else if (sourceIndexPath.row > 0 && proposedDestinationIndexPath.row == 0)
    {
        NSLog(@"Middle -> Top");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].detailTextLabel.text = @"Middle";
    }
    // Middle -> Bottom
    else if (sourceIndexPath.row < lastRow && proposedDestinationIndexPath.row == lastRow)
    {
        NSLog(@"Middle -> Bottom");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:lastRow inSection:0]].detailTextLabel.text = @"Middle";
    }
    // Bottom -> Middle
    else if (sourceIndexPath.row == lastRow && proposedDestinationIndexPath.row == lastRow-1)
    {
        NSLog(@"Bottom -> Middle");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:(lastRow-1) inSection:0]].detailTextLabel.text = @"Last";
    }
    // Bottom -> Bottom (user is screwing around, AGAIN)
    else if (sourceIndexPath.row == lastRow && proposedDestinationIndexPath.row == lastRow)
    {
        NSLog(@"Bottom -> Bottom");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:(lastRow-1) inSection:0]].detailTextLabel.text = @"Middle";
    }
    // Middle -> Top -> Middle (ugh)
    else if (sourceIndexPath.row > 0 && sourceIndexPath.row < lastRow && proposedDestinationIndexPath.row == 1)
    {
        NSLog(@"Middle -> Top -> Middle");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].detailTextLabel.text = @"First";
    }
    // Middle -> Bottom -> Middle (ugh x2)
    else if (sourceIndexPath.row > 0 && sourceIndexPath.row < lastRow && proposedDestinationIndexPath.row == lastRow-1)
    {
        NSLog(@"Middle -> Bottom -> Middle");
        [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:lastRow inSection:0]].detailTextLabel.text = @"Last";
    }

    return proposedDestinationIndexPath;
}


You should be updating your data array as the user edits it. Once you update your new array, then you can call reloadData to refresh the UITableView.

0

精彩评论

暂无评论...
验证码 换一张
取 消