Создание двух UIScrollViews сопровождается прокруткой друг друга
Как бы я сделал два вида прокрутки, следуя за прокруткой друг друга?
Например, у меня есть вид прокрутки (A) слева от экрана, содержимое которого может перемещаться вверх и вниз, но не влево и вправо. Просмотр прокрутки B соответствует вверх и вниз по A, но также может прокручиваться влево и вправо. Прокрутка A всегда находится на экране.
-----------------------------------------------------------
| | |
| | |
| | |
| A | B |
| | |
| scrolls | |
| up & down | scrolls all directions |
| | |
-----------------------------------------------------------
Как мне сделать так, чтобы прокрутка вверх и вниз (любого вида) также прокручивала другую прокрутку в том же направлении вверх-вниз? Или есть другой способ сделать это?
Ответы
Ответ 1
Установите делегат прокрутки в виде A, который будет вашим контроллером просмотра... затем...
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint offset = scrollViewB.contentOffset;
offset.y = scrollViewA.contentOffset.y;
[scrollViewB setContentOffset:offset];
}
Если вы хотите, чтобы оба они следовали друг за другом, установите делегат для обоих из них и используйте...
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if([scrollView isEqual:scrollViewA]) {
CGPoint offset = scrollViewB.contentOffset;
offset.y = scrollViewA.contentOffset.y;
[scrollViewB setContentOffset:offset];
} else {
CGPoint offset = scrollViewA.contentOffset;
offset.y = scrollViewB.contentOffset.y;
[scrollViewA setContentOffset:offset];
}
}
Вышеупомянутый может быть реорганизован, чтобы иметь метод, который принимает в двух списках прокрутки и соответствует одному другому.
- (void)matchScrollView:(UIScrollView *)first toScrollView:(UIScrollView *)second {
CGPoint offset = first.contentOffset;
offset.y = second.contentOffset.y;
[first setContentOffset:offset];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if([scrollView isEqual:scrollViewA]) {
[self matchScrollView:scrollViewB toScrollView:scrollViewA];
} else {
[self matchScrollView:scrollViewA toScrollView:scrollViewB];
}
}
Версия Swift 3:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == scrollViewA {
self.synchronizeScrollView(scrollViewB, toScrollView: scrollViewA)
}
else if scrollView == scrollViewB {
self.synchronizeScrollView(scrollViewA, toScrollView: scrollViewB)
}
}
func synchronizeScrollView(_ scrollViewToScroll: UIScrollView, toScrollView scrolledView: UIScrollView) {
var offset = scrollViewToScroll.contentOffset
offset.y = scrolledView.contentOffset.y
scrollViewToScroll.setContentOffset(offset, animated: false)
}
Ответ 2
Я попробовал ответить Саймон Ли на iOS 11. Это сработало, но не очень хорошо. Два вида прокрутки были синхронизированы, но с использованием его метода прокрутки отображали эффект инерции (когда он продолжает прокручиваться после отпускания пальца) и эффект подпрыгивания. Я думаю, это связано с тем, что установка метода contentOffset
через setContentOffset(offset, animated: false)
вызывает циклические вызовы метода делегата scrollViewDidScroll(_ scrollView: UIScrollView)
(см. этот вопрос)
Вот решение, которое работало для меня на iOS 11:
// implement UIScrollViewDelegate method
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == self.scrollViewA {
self.syncScrollView(self.scrollViewB, toScrollView: self.scrollViewA)
}
else if scrollView == self.scrollViewB {
self.syncScrollView(self.scrollViewA, toScrollView: scrollViewB)
}
}
func syncScrollView(_ scrollViewToScroll: UIScrollView, toScrollView scrolledView: UIScrollView) {
var scrollBounds = scrollViewToScroll.bounds
scrollBounds.origin.y = scrolledView.contentOffset.y
scrollViewToScroll.bounds = scrollBounds
}
Поэтому вместо установки contentOffset
мы используем свойство bounds
для синхронизации другого scrollView с тем, который был прокручен пользователем. Таким образом, метод делегата scrollViewDidScroll(_ scrollView: UIScrollView)
не вызывается циклически, и прокрутка происходит очень плавно и с инерционными и прыгающими эффектами, как при одном прокрутке.