UIScrollView. Есть мысли о реализации "бесконечной" прокрутки / масштабирования?
Итак, UITableView поддерживает по существу "бесконечную" прокрутку. Там может быть предел, но эта присоска может прокручивать в течение долгого времени. Я хотел бы имитировать это поведение с помощью UIScrollView, но есть два фундаментальных препятствия:
1) scrollView.contentSize фиксируется во время создания. 2) масштабирование может превратить любую схему ленивой загрузки в ад, поскольку это может привести к взрыву данных.
Другие обдумывали эту идею? Да, я знаю, мы говорим о воссоздании Google Maps здесь. Любое понимание будет высоко ценится.
Ура, Дуг
5 ответов
Хотя невозможно создать действительно бесконечный UIScrollView, есть несколько простых приемов, которые вы можете использовать для эмуляции этого поведения.
- Обработка фиксированного
contentSize
: иметь представление фиксированного размера, обработанное представлением прокрутки, и при запуске или создании экземпляра установить смещение содержимого так, чтобы вы видели середину обработанного представления. Затем просто просмотрите смещение содержимого (используя KVO или другой метод), и, если вы приближаетесь к какому-либо краю, обновите содержимое представления новым набором содержимого (смещение соответствующим образом) и сбросьте представление прокрутки.contentOffset
свойство быть в середине. - Обработка масштабирования: сделайте что-то похожее, только в этот раз смотрите коэффициент масштабирования в представлении прокрутки. Всякий раз, когда он достигает определенной точки, сделайте некоторые манипуляции с любыми данными, которые вы представляете, чтобы они выглядели увеличенными, затем сбросьте коэффициент масштабирования до 1,0. Например, если вы прокручиваете изображение и оно увеличивается в два раза, программно примените какое-либо преобразование, чтобы сделать изображение в два раза больше, а затем сбросьте коэффициент масштабирования вида прокрутки до 1,0. Изображение все равно будет выглядеть увеличенным, но при просмотре с прокруткой можно будет продолжать увеличивать изображение при необходимости. (Google Maps делает еще один шаг вперед, когда лениво загружает более подробные представления по мере увеличения масштаба пользователя - вы можете или не можете реализовать это.)
Я только что закончил реализацию бесконечного свитка для меня. В моей реализации у меня есть UITableViewCell с scrollView и навигационными кнопками. ScrollView содержит x видов с одинаковой шириной. представления располагаются горизонтально, и подкачка включена.
scrollView.clipsToBounds = YES;
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
scrollView.showsHorizontalScrollIndicator = NO;
Мой кодлогика похожа на следующее:
- В моей функции инициализации я
- создать все виды (для вида прокрутки) и
- положить их в массив и
- добавить их в scrollView
Затем я вызываю функцию, которая вычисляет в цикле позиции для каждого вида (каждый раз, когда вы обнаруживаете прокрутку, эту функцию тоже нужно будет вызывать). Он всегда берет первый элемент массива и устанавливает фрейм в (0,0,...,...), второй с (i*width,0,....,....) и т. Д. на. Вызываемая функция выглядит так:
- (void)updateOffsetsOfViews{ int xpos = 0; for (int i=0; i<[views count]; i++) { UIImageView *_view = [views objectAtIndex:i]; CGRect aFrame = _view.frame; aFrame.origin.x = xpos; aFrame.origin.y = 0.0; _view.frame = aFrame; xpos += viewWidth; } float center = 0; if(fmod([views count],2) == 1){ center = viewWidth * ([views count]-1)/2; }else { center = viewWidth * [views count]/2; } [scrollView setContentOffset:CGPointMake(center, 0)]; lastOffset = center; }
Затем (все еще в процессе инициализации) я добавляю наблюдателя
[scrollView addObserver:self forKeyPath:@"contentOffset" options:0 context:nil];
поэтому каждый раз, когда что-то изменяется в scrollView, я вызываю функцию (наблюдаю за именем): она выглядит так:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { UIImageView *_viewFirst = (UIImageView *)[views objectAtIndex:0]; if ( fmod([scrollView contentOffset].x,viewWidth) == 0.0) { if ([scrollView contentOffset].x > lastOffset) { [views removeObjectAtIndex:0]; [views addObject:_viewFirst]; [self updateOffsetsOfViews]; }else if ([scrollView contentOffset].x < lastOffset) { UIImageView *_viewLast = (UIImageView *)[views lastObject]; [views removeLastObject]; [views insertObject:_viewLast atIndex:0]; [self updateOffsetsOfViews]; } } }
А в dealloc или viewDidUnload (зависит от того, как вы это реализуете) не забудьте удалить наблюдателя.
[scrollView removeObserver:self forKeyPath:@"contentOffset"];
Надеюсь, что это поможет, вы можете заметить некоторые накладные расходы, но в моей реализации я также поддерживаю прокрутку сразу на 5 страниц (ну... без ограничений) и автоматическую прокрутку и т. Д., Чтобы вы могли увидеть что-то, что можно было бы выбросить.
Пример проекта StreetScroller от Apple демонстрирует, как выполнять бесконечную прокрутку в UIScrollView.
Имейте в виду, что когда анимация прокручивается, contentOffset
меняется много раз, не только страница за страницей, но и с каждым шагом анимации.
Возможно постановка contentSize
до некоторого гигантского значения, а затем перемещая ограниченное количество базовых видов вокруг, чтобы отследить позицию вида, как в примере Tiling, добьется цели.
Чтобы уменьшить возможность достижения в конечном итоге края и необходимости внезапного повторного помещения вида (что отменяет любую прокрутку, находящуюся в движении), время от времени представление можно повторно вводить, когда оно неподвижно.
Во всяком случае, это то, что я собираюсь попробовать.