Настройка contentOffset программно запускает scrollViewDidScroll
У меня есть несколько UIScrollView
на странице. Вы можете прокручивать их самостоятельно или блокировать их вместе и прокручивать их как один. Проблема возникает, когда они заблокированы.
Я использую UIScrollViewDelegate
и scrollViewDidScroll:
для отслеживания движения. Я запрашиваю contentOffset
из UIScrollView
, который был изменен, а затем отразил изменения в других видах прокрутки, установив их свойство contentOffset
в соответствие.
Великий.... кроме того, что я заметил много дополнительных звонков. Программное изменение contentOffset
моих представлений прокрутки запускает метод делегата scrollViewDidScroll:
для вызова. Я попытался использовать setContentOffset:animated:
вместо этого, но я все еще получаю триггер на делетете.
Как я могу программным образом модифицировать свои программные объекты контента, чтобы не запускать scrollViewDidScroll:
?
Замечания по реализации....
Каждый UIScrollView
является частью пользовательского UIView
, который использует шаблон делегирования для обратного вызова к представляющему подклассу UIViewController
, который обрабатывает координаты различных значений contentOffset
.
Ответы
Ответ 1
Можно изменить смещение содержимого UIScrollView
без запуска обратного вызова делегата scrollViewDidScroll:
, установив границы UIScrollView
с исходным значением, установленным на желаемое смещение содержимого.
CGRect scrollBounds = scrollView.bounds;
scrollBounds.origin = desiredContentOffset;
scrollView.bounds = scrollBounds;
Ответ 2
Try
id scrollDelegate = scrollView.delegate;
scrollView.delegate = nil;
scrollView.contentOffset = point;
scrollView.delegate = scrollDelegate;
Работал для меня.
Ответ 3
Как использовать существующие свойства UIScrollView?
if(scrollView.isTracking || scrollView.isDragging || scrollView.isDecelerating) {
//your code
}
Ответ 4
Упрощая ответ @Tark, вы можете поместить прокрутку без стрельбы scrollViewDidScroll
в одну строку следующим образом:
scrollView.bounds.origin = CGPoint(x:0, y:100); // whatever values you'd like
Ответ 5
Это не прямой ответ на вопрос, но если вы получаете то, что кажется ложным, такие сообщения, это может быть ТАКЖЕ, потому что вы меняете границы. Я использую код примера Apple с методом "tilePages", который удаляет и добавляет subview в scrollview. Это редко приводит к появлению дополнительных сообщений scrollViewDidScroll:, вызываемых немедленно, поэтому вы попадаете в рекурсию, которую вы точно не ожидали. В моем случае я получил отвратительное невозможное найти крах.
То, что я закончил, заключалось в очередности вызова в главной очереди:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if(scrollView == yourScrollView) {
// dispatch fixes some recursive call to scrollViewDidScroll in tilePages (related to removeFromSuperView)
// The reason can be found here: http://stackoverflow.com/questions/9418311
dispatch_async(dispatch_get_main_queue(), ^{ [self tilePages]; });
}
}
Ответ 6
Другой подход заключается в добавлении некоторой логики в делегат scrollViewDidScroll, чтобы определить, было ли изменение смещения содержимого запрограммировано или нажато пользователем.
- Добавить логическую переменную isManualScroll в ваш класс.
- Задайте начальное значение false.
- В scrollViewWillBeginDragging задано значение true.
- В вашей проверке scrollViewDidScroll убедитесь, что это правда, и ответьте только в том случае, если она есть.
- В scrollViewDidEndDecelerating установите значение false.
- В scrollViewWillEndDragging добавьте логику, чтобы установить значение false, если скорость равна 0 (поскольку scrollViewDidEndDecelerating не будет вызываться в этом случае).