Принудительное перемещение UITableView к вершинам ячеек

Есть ли способ заставить UITableViews прокручивать ячейку в ячейку? То есть верхняя часть Table View всегда является вершиной UITableViewCell.

Я попробовал флаг прокрутки, но, похоже, прокручивает целые "страницы". Я просто хочу прокрутку ячейки в ячейку.

Спасибо

Ответ 1

UTTableView является подклассом UIScrollView, поэтому вы можете использовать метод scrollViewDidScroll для изменения позиции прокрутки TableView после прокрутки.

Вы можете использовать tableView.contentOffset, чтобы получить, где находится текущая позиция прокрутки. И, разделив его на значащее число, вы можете получить, какая ячейка находится сверху.

int cellIndex = tableView.contentOffset / cellHegiht;

Или вы можете получить видимую в данный момент ячейку в центре (сверху, снизу) следующим образом:

NSArray *indexPathsForVisibleRows = [tableView indexPathsForVisibleRows];
NSIndexPath *selectedIndexPath = [indexPathsForVisibleRows objectAtIndex:(indexPathsForVisibleRows.count / 2)]; //this gets center cell

После вычисления того, какая ячейка должна быть нажата по ее краю сверху (или внизу), вы можете исправить дрейф от края ячейки, вызвав:

[tableView scrollToRowAtIndexPath:selectedIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];

Вы можете использовать методы UIScrollViewDelegate для активации привязки. Вы можете активировать либо при завершении анимации прокрутки, либо во время анимации. Это создаст другое взаимодействие с пользователем и не может сказать, что лучше, чем другое.

Но просто внедряя следующий метод, и ничто другое не выглядит как мой любимый:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
                     withVelocity:(CGPoint)velocity
              targetContentOffset:(inout CGPoint *)targetContentOffset {
    int cellHeight = 41;
    *targetContentOffset = CGPointMake(targetContentOffset->x,
                                       targetContentOffset->y - (((int)targetContentOffset->y) % cellHeight));
}

Этот метод вызывается, когда пользователь прикасается к TableView для уведомления приложения. targetContentOffset - это переменная inout, поэтому вы можете установить конечную позицию прокрутки во время анимации. Используя right cellHeight, ваш TableView будет всегда привязываться к ячейкам.

Ответ 2

Если у вас есть разделы, я нашел этот наиболее надежный подход:

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate(BOOL)decelerate {
    if (decelerate == NO) {
        [self autoAdjustScrollToTop];
    }
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [self autoAdjustScrollToTop];
} 
- (void)autoAdjustScrollToTop {
    // compare the top two visible rows to the current content offset
    // and auto scroll so that the best row is snapped to top
    NSArray *visibleRows = [self.tableView indexPathsForVisibleRows];
    NSIndexPath *firstPath = visibleRows[0];
    NSIndexPath *secondPath = visibleRows[1];
    CGRect firstRowRect = [self.tableView rectForRowAtIndexPath:firstPath];
    [self.tableView scrollToRowAtIndexPath:(firstRowRect.origin.y > self.tableView.contentOffset.y ? firstPath : secondPath) atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

Ответ 3

Хотя абсолютно правильно, я не нашел ответ by @randle очень полезным. Я прочитал документацию разработчиков, и я был еще более смущен. Как-то я наконец выяснил, насколько прост был ответ, но иногда нам нужна небольшая, но большая помощь, чем "называть этот метод". См. Комментарий.//прокручиваем строку! здесь:

- (BOOL)textFieldShouldReturn:(UITextField *)textField 
{
    if (textField == self.firstInput) {
        [self.secondInput becomeFirstResponder];

        // scroll to row!
        [self.tableView scrollToRowAtIndexPath: // use the method
             [NSIndexPath indexPathForRow:1     // get 2nd row (nth row...)
                                inSection:0]    // in 1st section (...)
                         // set position: you can use bottom, middle or top.
                         atScrollPosition:UITableViewScrollPositionBottom  
                                 animated:YES]; // YES or NO.

    } else if (textField == self.secondInput) {
        [textField resignFirstResponder];
    }
    return YES;
}

Теперь это для статического cellView. Я знаю количество строк, я знаю, в какую строку я собираюсь. Это может быть расширено для лучшего кода и доступа к переменным программным путем, но оно показывает, КАК этот код работает на практике на низком уровне.

Я надеюсь, что это добавит слой полезности всем, кто ищет форум.

Я сделал полную запись метода здесь: http://iosanswers.blogspot.com/2012/02/table-view-forms-scroll-to-selected.html

Ответ 4

Этот подход обрабатывает представление таблицы с различными высотами строк. Предполагается, что представление таблицы имеет один раздел.

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
                     withVelocity:(CGPoint)velocity
              targetContentOffset:(inout CGPoint *)targetContentOffset {

    // Find the row where the animation will currently end.
    NSInteger targetRow = [[self.tableView indexPathForRowAtPoint:*targetContentOffset] row];

    // Tell the animation to end at the top of that row.
    *targetContentOffset = [self offsetForTopOfRow:targetRow];
}

Смещение вычисляется с помощью этого вспомогательного метода, который суммирует высоты всех строк над целевой строкой.

- (CGPoint)offsetForTopOfRow:(NSInteger)row {

    CGPoint offset = CGPointZero;

    for (int i = 0; i < row; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
        CGFloat height = [self.tableView.delegate tableView:self.tableView heightForRowAtIndexPath:indexPath];
        offset.y += height;
    }

    return offset;
}

Ответ 5

Вам просто нужно вызвать scrollToRowAtIndexPath:atScrollPosition:animated: и передать ему правильный путь указателя для нужной ячейки.

Ответ 6

Это хорошо работает, если у вас есть разделы и строки со статическими высотами.

func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    // Adjust target offset so that cells are snapped to top
    let cellHeight: CGFloat = 44
    let headerHeight: CGFloat = 30
    let section = (indexPathsForVisibleRows?.first?.section ?? 0) + 1
    targetContentOffset.memory.y -= (targetContentOffset.memory.y % cellHeight) - (CGFloat(sectionIndex) * headerHeight)
}