Принудительное перемещение 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)
}