Может ли кто-нибудь точно описать поведение -[UIScrollView zoomToRect:animated:]? Кажется, что этот метод действительно делает некоторые сложные вещи, но документация Apple по нему очень скудна.

Я получаю непредсказуемое поведение этого метода, когда размер содержимого меньше размера прокрутки по ширине и / или высоте. В некоторых случаях этот метод заставляет представление прокрутки иметь отрицательное смещение содержимого, когда оно должно быть 0. Передавая немного другие прямоугольники, он оставляет смещение содержимого равным 0, как я и ожидал.

Чтобы продемонстрировать это странное поведение, я создал пример проекта с представлением прокрутки размера (200, 200) , содержащим представление содержимого размером (100, 100) . Я ожидал, что при масштабировании до rect ((0, 0), (200, 200)) представления содержимого содержимое должно оставаться в верхнем левом углу (т.е. ничего не должно происходить ). Однако на самом деле это заставляет содержимое прокручиваться в нижний правый угол границ представления прокрутки (смещение содержимого (-100, -100)). Почему это происходит?

Screen Recording

Вот код в моем примере проекта:

@implementation RootViewController

- (void)loadView {
    self.view = [[UIView alloc] init];

    self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    self.scrollView.delegate = self;
    self.scrollView.backgroundColor = [UIColor whiteColor];
    self.scrollView.minimumZoomScale = .5;
    self.scrollView.maximumZoomScale = 4;

    self.contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    self.contentView.backgroundColor = [UIColor redColor];
    [self.contentView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)]];

    [self.scrollView addSubview:self.contentView];
    self.scrollView.contentSize = self.contentView.frame.size;
    [self.view addSubview:self.scrollView];
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return self.contentView;
}

- (void)handleTap {
    [self.scrollView zoomToRect:CGRectMake(0, 0, 200, 200) animated:YES]; // Try changing to 199, 199 to get completely different behavior
}

@end

Спасибо за любые идеи! Прямо сейчас я предполагаю, что UIScrollView просто не предназначен для отображения содержимого меньше его собственного размера. Мой вариант использования заключается в том, что у меня может быть представление содержимого, которое шире, чем представление прокрутки, но короче по высоте, и мне нужно иметь возможность программно прокручивать либо правый, либо левый конец этого представления.

4
tboyce12 28 Май 2014 в 04:09

2 ответа

Лучший ответ

Если у кого-то нет лучшего ответа, я собираюсь сделать вывод, что вызов -zoomToRect:animated: имеет неопределенные результаты, когда результирующий contentSize меньше, чем размер bounds в любом измерении. Другими словами, контент должен быть больше, чем прокрутка, если вы хотите быть в безопасности.

3
tboyce12 28 Май 2014 в 04:06

Если кому-то интересно, вот что я могу сделать в этом случае. Я собираюсь посмотреть, хорошо ли он работает с модульными тестами для подкласса представления прокрутки, который я реализую в своем реальном проекте. Однако это не отвечает на исходный вопрос: «Может ли кто-нибудь точно описать поведение -[UIScrollView zoomToRect:animated:]?» так что я все еще надеюсь получить больше ответов.

Что ж, вот оно (я ненавижу подобные хакеры):

@implementation TBScrollView // Subclass of UIScrollView

- (void)setContentOffset:(CGPoint)contentOffset {
    contentOffset.x = MAX(contentOffset.x, 0);
    contentOffset.y = MAX(contentOffset.y, 0);
    [super setContentOffset:contentOffset];
}

- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated {
    contentOffset.x = MAX(contentOffset.x, 0);
    contentOffset.y = MAX(contentOffset.y, 0);
    [super setContentOffset:contentOffset animated:animated];
}

@end

РЕДАКТИРОВАТЬ: К сожалению, это имеет неприятный побочный эффект, заключающийся в том, что вы больше не можете отскакивать от прокрутки с левой стороны для больших изображений, где это должно быть разрешено (требуется отрицательное смещение содержимого). Я собираюсь найти другое решение для моего варианта использования.

РЕДАКТИРОВАТЬ 2: Я обошел вышеупомянутый побочный эффект, отключив отрицательные смещения содержания только во время анимации -zoomToRect:animated:. Я объявил свойство BOOL, установил для него значение YES перед вызовом -zoomToRect:animated:, а затем снова установил его на NO, если animated был NO. В противном случае я устанавливаю для свойства значение NO во время -scrollViewDidEndScrollingAnimation: (вызывается, если -zoomToRect:animated: не вызывает каких-либо изменений в масштабе) и -scrollViewDidEndZooming:withView:atScale: (вызывается, если -zoomToRect:animated: вызывается вызывают изменение масштаба). Это своего рода хакерское решение, и я беспокоюсь, что оно может сломаться с будущим выпуском iOS, но, по крайней мере, у меня все это поддерживается модульными тестами :)

2
tboyce12 28 Май 2014 в 04:11