简体   繁体   中英

Saving state of UITableView cell accessory?

I have gesture recognisers set up on my table view.

  • Swipe to the right and the accessory changes to an image of a tick
  • Swipe to the left and is changes to a chevron image

If a cell is tapped, it loads a local HTML file.

If you swipe to the right, the tick appears as it should. However, if you then tap a cell to view a HTML file and come back to the table view, the image reverts to the chevron.

What's the best way to ensure the tick stays as it should?


EDIT

Further code:

From 'viewDidLoad':

UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                                                 action:@selector(handleSwipeRight:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[self.tableView addGestureRecognizer:recognizer];

recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                       action:@selector(handleSwipeLeft:)];
//recognizer.delegate = self;
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[self.tableView addGestureRecognizer:recognizer];


- (void)handleSwipeLeft:(UISwipeGestureRecognizer *)gestureRecognizer
{
//Get location of the swipe
CGPoint location = [gestureRecognizer locationInView:self.tableView];

//Get the corresponding index path within the table view
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];

//Check if index path is valid
if(indexPath)
{
    //Get the cell out of the table view
    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

    //Update the cell or model

    cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"disclosure.png"]];
}
}

- (void)handleSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer
{
CGPoint location = [gestureRecognizer locationInView:self.tableView];

NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];

if(indexPath)
{
    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

    // cell.accessoryType = UITableViewCellAccessoryCheckmark;
    cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"tick.png"]];
}

}

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

static NSString *simpleTableIdentifier = @"MFGCell";

MFGCell *cell = (MFGCell *) [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];

if (cell == nil) {
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MFGCell" owner:self options:nil];
    cell = [nib objectAtIndex:0];
}

cell.itemTitle.text = [item objectAtIndex:indexPath.row];
cell.itemDescription.text = [description objectAtIndex:indexPath.row];
cell.itemImageView.image = [UIImage imageNamed:[icons objectAtIndex:indexPath.row]];

return cell;
}

In reaction to the user's swipe you should store the user's choice (eg in a private instance variable of type NSMutableArray ). When the user comes back to the table view you can then reuse the information in your tableView:cellForRowAtIndexPath: to setup the cell with the correct accessory style.

Property declaration:

@property(nonatomic, retain) NSMutableArray* _accessoryStyle;

Synthesize the property. Then add this snippet to the bottom of handleSwipeLeft: to store the user's choice:

- (void)handleSwipeLeft:(UISwipeGestureRecognizer *)gestureRecognizer
{
  [...]
  NSNumber* number = [numberWithInt:0];
  [_accessoryStyle replaceObjectAtIndex:indexPath.row withObject:number];
}

Add a similar snippet to the bottom of handleSwipeRight: :

- (void)handleSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer
{
  [...]
  NSNumber* number = [numberWithInt:1];
  [_accessoryStyle replaceObjectAtIndex:indexPath.row withObject:number];
}

In tableView:cellForRowAtIndexPath: :

NSString* accessoryImageName;
NSNumber* number = [_accessoryStyle objectAtIndex:indexPath.row];
switch ([number intValue])
{
  case 0:
    accessoryImageName = @"disclosure.png";
    break;
  case 1:
    accessoryImageName = @"tick.png";
    break;
  default:
    // replace with your error handling code
    return nil;
}
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:accessoryImageName]];

For all this to work you need to initialize the _accessoryStyle array with the same number of elements that you expect your table view to have cells. For instance, in your view controller's viewDidLoad :

- (void) viewDidLoad
{
  [super viewDidLoad];

  self._accessoryStyle = [NSMutableArray arrayWithCapacity:0];
  NSNumber* defaultAccessoryStyle = [numberWithInt:0];
  int numberOfRows = 17;  // get the real number from somewhere
  for (int index = 0; index < numberOfCells; ++index)
    [_accessoryStyle addObject:defaultAccessoryStyle];
}

And to balance this you need to add

- (void) viewDidUnload
{
  [super viewDidUnload];
  self._accessoryStyle = nil;
}

There is still much room for improvement:

  • Find better variable names
  • Use an enumeration for the different styles instead of just hardcoded numbers 0 and 1
  • Do not allocate a new UIImageView for each table view cell, just allocate two of them and use the right one depending on the accessory style

For your problem, there is an underlying logic issue because there is either a swipe left event firing when it should not or the views are just being unloaded and resetting to default. See if you can log when the events fire; otherwise the state of the view should be preserved. Also what I would do is add an extra state variable like int currentCellState that you change when you enter your different states to keep track of your states. Then in your viewDIdLoad make sure that all your data and your view are in sync, ie the value of currentCellState matches the state of your view.

The best way to do this is to put the images/buttons you have in an array, and each time the view loads it shows the item which index is selected.. in order to do this, the swipeMethode should be modified to something like this

-(void)swipeMethod: (UISwipeGestureRecognizer *) sender
{
    if(sender.direction == 
        UISwipeGestureRecognizerDirectionLeft && index < [myArray count]){   
        [self setSelectedIndex:index+1  animated:YES];  
        index++;
    }else if (sender.direction == UISwipeGestureRecognizerDirectionRight && index > 0) {
        [self setSelectedIndex:index-1 animated:YES]; 
        index--;
    }else {
        return;
    }
}

in the viewDidLoad add this code:

    leftRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeMethod:)];
    [leftRecognizer setDirection: UISwipeGestureRecognizerDirectionLeft];
    [self.tableView addGestureRecognizer:leftRecognizer];

    rightRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeMethod:)];
    [rightRecognizer setDirection: UISwipeGestureRecognizerDirectionRight];
    [self.tableView addGestureRecognizer:rightRecognizer];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM