В iOS 4.0 почему UIScrollView zoomToRect: анимированный: не запускать делегаты scrollViewDidScroll или scrollViewDidZoom во время анимации?
Мне нужно внимательно следить за масштабом представления прокрутки, чтобы я мог обновлять элементы представления контента (подматрица, управляющая несколькими CALayers) в соответствии с анимированным увеличением прокрутки.
В iOS 3.1 все работает так, как ожидалось, я использую zoomToRect: анимированный: и сообщение scrollViewDidScroll: сообщение UIScrollViewDelegate вызывается повторно во время анимации, позволяя мне обновлять элементы subview в соответствии с фактическое масштабирование.
Тот же самый код в iOS 4.0 не показывает того же поведения. Когда я вызываю zoomToRect: animated:, делегаты (scrollViewDidScroll: и scrollViewDidZoom) получают только вызов один раз, что делает мои дочерние элементы деинхронизированными до завершения анимации. Фактически, подэлементы сразу же прыгают, а затем увязаны анимацией масштабирования, пока все не окажется в правильном месте. Это как если бы анимация не собирала модификации на CALayers subviews.
Я пробовал анимацию вручную с блоками анимации, но ситуация такая же, никаких прогрессивных вызовов обратного вызова. Я также пробовал KVO, но мне непонятно, как я буду использовать анимацию, управляемую UIScrollView.
Есть ли обходной путь для iOS 4, который позволил бы мне подтолкнуть значение шкалы к моим подзонам, когда анимированная шкала UIScrollView?
Ответы
Ответ 1
Жестокий, но работает.
Определите некоторые свойства:
@property (nonatomic, strong) UIView *zoomedView;
@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic) CGFloat currentScale;
Сообщите UIScrollView
, который UIView
будет увеличен:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.zoomedView;
}
Зарегистрируйте для CADisplayLink
тиков. Он также запускает Core Animation, поэтому его будут пинать с одинаковыми интервалами:
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTick)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
Проверить zoomedView presentationLayer
для текущих значений.
- (void)displayLinkTick
{
CALayer *zoomedLayer = self.zoomedView.layer.presentationLayer;
CGFloat scale = zoomedLayer.transform.m11;
if (scale != self.currentScale) {
self.currentScale = scale; // update property
// the scale has changed!
}
}
Ответ 2
В IOS 4.0 анимация выполняется ОС - я предполагаю использовать максимально возможное аппаратное ускорение на основе GPU. В качестве недостатка этого становится сложнее оживить значения, полученные из другого (анимированного) значения. Как и в вашем случае, позиции подзонов, которые зависят от уровня масштабирования UIScrollView.
Чтобы это произошло, вы должны настроить анимацию подвью, чтобы идти параллельно с анимацией масштабирования. Попробуйте что-то вроде:
[UIView animateWithDuration:0.5 delay:0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
theScrollView.zoomScale = zoomScale;
// layout the subviews here
} completion:^(BOOL finished) {}];
Это должно задавать свойства фрейма субподробных объектов из одного и того же контекста анимации, и поэтому они должны быть анимированы вместе ОС.
См. также ответы на этот вопрос: Как заставить UIScrollView отправлять сообщения scrollViewDidScroll во время анимации
Ответ 3
Можно ли обновить все подзоны в блоке анимации (или начать /commitAnimation )?
Что-то вроде:
[self zoomToRect:zoomRect animated:YES];
[UIView animateWithDuration:1.0
animations:^ {
// change your subviews
}
];
Ответ 4
Зарегистрируйте для KVO свойства zoomScale
UIScrollView
после вызова zoomToRect:animated:
.
[scrollView addObserver:self
forKeyPath:@"zoomScale"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
Затем реализуем этот метод:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqual:@"zoomScale"]) {
// use the new zoomScale value stored
// in the NSKeyValueChangeNewKey change
// dictionary key to resize your subviews
}
// be sure to call the super implementation
// if the superclass implements it
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
Проверьте KVO documentation.