Obtain an NSIndexPath for an "off-screen" UITableViewCell from the index of a data source array

StackOverflow https://stackoverflow.com/questions/23405707

Pregunta

Original Title: Scroll to specific UITableViewCell in a UITableView with dynamic multiple sections

New title: Obtain an NSIndexPath for an "off-screen" UITableViewCell from the index of a data source array

I want to be able to smoothly scroll a table view until a previously selected cell is shown on screen.

The problem arises because I cannot find a solution to determine the indexPath of a cell before it is loaded by tableview:cellForRowAtIndexPath:.

The UITableViewController data source is a NSFetchedResultsController that returns multiple sections.

I have read these SO questions, however they all provide a solution to the problem with only one section:

I have included code below - it works - however the scroll motion is uneven (start/stop) - the code scrolls a row, assesses whether the next row contains the data related to a previously selected cell, and if not scrolls to the next row, and so on and so on... ... until the previously selected cell is found and is on screen.

This code does not work on a device running iOS6.

Anyone have any ideas about how to scroll to the previously selected cell smoothly under iOS 7, and even better if the solution can work under iOS 6.

UPDATE:

  • New question title,
  • thanks to @dasblinkenlight, now working on determining how to obtain an NSIndexPath for an "off-screen" UITableViewCell from the index of a data source array.

Using the enumeration option identified in the first SO question link above.

Updated code to be posted...


Existing Code

Properties.

@property (nonatomic, strong) NSIndexPath *indexPathCurrent;
@property (nonatomic) BOOL selectedCellIsVisibleOnScreen;

The "action" code sits at the end of my tableview:cellForRowAtIndexPath: method.

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

    <... code to configure cell...>

    BOOL isChecked = NO;

    <... code to set the value for isChecked...>

    if (self.isIOS7 && !self.selectedCellIsVisibleOnScreen) {
        [self setIndexPathCurrent:indexPath];
        [self setSelectedCellIsVisibleOnScreen:isChecked];

        [self.tableView scrollToRowAtIndexPath:self.indexPathCurrent
                              atScrollPosition:UITableViewScrollPositionNone
                                      animated:YES];
    }
}

The property isIOS7 is determined elsewhere and is in place to disable this action for any device running iOS 6, as this code causes hectic behaviour in the table view when executed under iOS 6.

New Code

to be advised...

¿Fue útil?

Solución

My answer with thanks to @dasblinkenlight for pointing me in the right direction...

Properties:

// public - receives an array of values for the 'previously selected cells'
@property (nonatomic, strong) NSArray *arrayObjects;            
// private
@property (nonatomic, strong) NSIndexPath *indexPathObjectFromArray;

In viewWillAppear:

    NSManagedObject *selectManagedObjects = nil;
    NSManagedObject *checkManagedObject = nil;
    NSFetchedResultsController *frc = nil;
    NSArray *fetchedObjects = nil;
    NSInteger nofSectionsInTableView;
    NSInteger nofRowsInSection;
    NSInteger currentSection = 0;
    NSInteger currentRow = 0;

    // possible more than one object selected - we want the last or bottom-most object 
    selectManagedObjects = self.arrayObjects.lastObject;

    frc = self.fetchedResultsController;
    fetchedObjects = frc.fetchedObjects;
    nofSectionsInTableView = frc.sections.count;

    while (currentSection < nofSectionsInTableView && self.indexPathObjectFromArray == nil) {
        nofRowsInSection = [[frc.sections objectAtIndex:currentSection] numberOfObjects];
        for (int sectionRow = 0; sectionRow < nofRowsInSection; sectionRow++) {
            checkManagedObject = [fetchedObjects objectAtIndex:currentRow];
            if (checkManagedObject == selectManagedObjects) {
                [self setIndexPathObjectFromArray:[NSIndexPath indexPathForRow:sectionRow
                                                                   inSection:currentSection]];
                break;
            }
            currentRow++;
        }
        currentSection++;
    }

In viewDidAppear:

    [self.tableView scrollToRowAtIndexPath:self.indexPathObjectFromArray
                          atScrollPosition:UITableViewScrollPositionNone
                                  animated:YES];

Note the use of UITableViewScrollPositionNone - this ensures that if the bottom-most previously selected cell is in the initial view (and therefore scrolling is not required), then no scrolling will occur.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top