У меня есть следующая цепочка подпредставлений:
UIViewController.view -+
|-> UIView (subclass) -+
| +-> UIToolbar
|
+------------------------> UIWebView
В подклассе я переопределяю его метод -touchesEnded:forEvent:
, чтобы скрыть и показать UIToolbar
одним касанием, через CAAnimation
, а также выдать NSNotification
, который заставляет контроллер представления скрыть свою панель навигации.
Если я не добавлю UIWebView
как подпредставление к представлению контроллера представления, то это работает правильно.
Если я затем добавлю UIWebView
как подпредставление представления контроллера представления, то UIToolbar
не появится, и я не получу эффект анимации. UIWebView
реагирует на прикосновения, а подкласс UIView
- нет. Однако уведомление действительно срабатывает, а панель навигации скрывается.
Как лучше организовать эти подпредставления так, чтобы:
-
UIToolbar
можно заставить скользить по экрану
- Видимый
UIWebView
по-прежнему может принимать обычные сенсорные события: увеличение / уменьшение и двойное касание для сброса уровня увеличения
Правильный ответ будет соответствовать обоим критериям.
EDIT
Я добился определенного прогресса в этом, но я не могу различить сенсорные события, и поэтому я запускаю метод скрытия / показа панели инструментов, когда он не должен запускаться.
Я установил свойство view контроллера представления в подкласс UIView
и вставил веб-представление в верхнюю часть массива -subviews
с помощью [self.view insertSubview:self.webView atIndex:0]
.
Я добавил следующий метод в подкласс UIView
:
- (UIView *) hitTest:(CGPoint) point withEvent:(UIEvent *)event {
UIView *subview = [super hitTest:point withEvent:event];
if (event.type == UIEventTypeTouches) {
[self toggleToolbarView:self];
// get touches
NSSet *touches = [event allTouches];
NSLog(@"subview: %@", subview);
NSLog(@"touches: %@", touches);
// individual touches
for (UITouch *touch in touches) {
switch (touch.phase) {
case UITouchPhaseBegan:
NSLog(@"UITouchPhaseBegan");
break;
case UITouchPhaseMoved:
NSLog(@"UITouchPhaseMoved");
break;
case UITouchPhaseCancelled:
NSLog(@"UITouchPhaseCancelled");
break;
case UITouchPhaseStationary:
NSLog(@"UITouchPhaseStationary");
break;
default:
NSLog(@"other phase...");
break;
}
}
}
return subview;
}
Метод -toggleToolbarView:
вызывает NSTimer
-тимированный CAAnimation
, который скрывает / показывает UIToolbar*
.
Проблема заключается в том, что комбинация перетаскивания приводит к срабатыванию -toggleToolbarView:
(а также к увеличению или уменьшению веб-представления). Я хотел бы, чтобы -toggleToolbarView:
запускался только при событии только для прикосновения.
Когда я вызываю вышеуказанный метод -hitTest:withEvent:
, похоже, что UIWebView
высасывает прикосновения. Два оператора NSLog
показывают, что UIView*
, который возвращается от родительского UIView*
s -hitTest:withEvent:
, является либо UIWebView
, либо UIToolbar
(когда он находится на экране и прикасается). Массив touches
пуст, и поэтому типы событий касания не могут быть распознаны.
Есть еще одна вещь, которую я попробую, но я хотел записать эту попытку здесь на случай, если у других будут быстрые предложения. Спасибо за вашу постоянную помощь.
РЕДАКТИРОВАТЬ II
Я добился некоторого прогресса в том, чтобы заставить UIWebView
сжимать / масштабировать и реагировать на двойное касание. Я также могу скрыть / показать панель инструментов с одним нажатием.
Вместо того чтобы связываться с приватным UIWebView
экземпляром UIScroller
, я получаю доступ к его внутреннему приватному UIWebDocumentView
. Но веб-представление в целом не перерисовывается должным образом после увеличения.
Что это означает: если мой документ содержит, например, векторную иллюстрацию в формате PDF или SVG, увеличение масштаба приводит к размытию содержимого, как если бы фрагменты изображения, составляющие визуализированное содержимое PDF или векторные иллюстрации, не воспроизводились отображается с новым коэффициентом увеличения.
В целях документирования этого я буду:
Позвоните UIView (subclass)
вместо ViewerOverlayView
UIWebView
называется ViewerWebView
Оба являются подклассами UIView
и UIWebView
, соответственно.
My ViewerWebView
содержит новый ivar (с @property
+ @synthesized
):
UIView *privateWebDocumentView;
(Этот UIView
на самом деле является указателем на экземпляр UIWebDocumentView
, но во избежание того, чтобы Apple пометила приложение отказом, я привел его к UIView
для простой передачи его событиям касания.)
Реализация ViewerWebView
переопределений -hitTest:withEvent:
- (UIView *) hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *_subview = [super hitTest:point withEvent:event];
self.privateWebDocumentView = _subview;
return _subview;
}
My ViewerOverlayView
содержит новые ивары (с @property
+ @synthesized
):
ViewerWebView *webView;
UIView *webDocumentView;
В реализации наложения я переопределяю -touchesBegan:withEvent:
, -touchesMoved:withEvent:
и -touchesEnded:withEvent:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.touchHasMoved = NO;
if (self.webView) {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
self.webDocumentView = [self.webView hitTest:touchPoint withEvent:event];
}
[super touchesBegan:touches withEvent:event];
[self.webDocumentView touchesBegan:touches withEvent:event];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
self.touchHasMoved = YES;
if (self.webView) {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
self.webDocumentView = [self.webView hitTest:touchPoint withEvent:event];
}
[super touchesMoved:touches withEvent:event];
[self.webDocumentView touchesMoved:touches withEvent:event];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(!self.touchHasMoved)
[self toggleToolbarView:self];
if (self.webView) {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
self.webDocumentView = [self.webView hitTest:touchPoint withEvent:event];
}
[super touchesEnded:touches withEvent:event];
[self.webDocumentView touchesEnded:touches withEvent:event];
}
В контроллере вида я делаю следующее:
Создание экземпляра ViewerOverlayView
и добавление его в качестве подпредставления свойства view
контроллера представления
Создание экземпляра ViewerWebView
контроллера представления и вставка его в конец массива подпредставлений
Установите свойство ViewerOverlayView
веб-представления для веб-представления контроллера представления
Итак, теперь мой прозрачный ViewerOverlayView
правильно передает события касания увеличения / растяжения / двойного касания в частный экземпляр UIWebDocumentView
экземпляра ViewerWebView
. UIWebDocumentView
затем изменяет размер.
Однако содержимое не перерисовывается с новым масштабом. Поэтому при масштабировании векторный контент (например, PDF, SVG) выглядит размытым.
Вот как выглядит изображение без масштабирования, красивое и резкое:
Here's what the view looks like when zoomed in, which is not as sharp as it would otherwise be without all this custom event munging:
Interestingly, I can only rescale between two zoom levels. Once I stop double-tap-stretching to zoom in at any level, it then "snaps back" to the frame you see in the image above.
I tried -setNeedsDisplay
on the ViewerWebView
and its inner UIWebDocumentView
instance. Neither method call worked.
Despite wanting to avoid private methods, because I want to eventually get this app approved, I also tried это предложение о доступе к приватному UIWebDocumentView
методу -_webCoreNeedsDisplay
:
[(UIWebDocumentView *)self.webDocumentView _webCoreNeedsDisplay];
Этот метод вызвал аварийное завершение работы приложения из unrecognized selector
исключения. Возможно, Apple изменила название этого метода с SDK 3.0 на 3.1.2.
Если не существует способа заставить веб-представление перерисовать его содержимое, я думаю, мне придется отказаться от прозрачного наложения и просто нарисовать веб-представление, чтобы заставить веб-представление работать должным образом. Это отстой!
Если у кого-то возникают мысли о перерисовке после масштабирования, пожалуйста, не стесняйтесь добавлять ответ.
Еще раз спасибо всем за ваш вклад. Кроме того, я не отменил награду за этот вопрос - я не знаю, почему она не была автоматически присуждена первому ответу в этой теме, поскольку я ожидал, что это произойдет из предыдущего опыта.
РЕДАКТИРОВАТЬ III
Я нашел эту веб-страницу, на которой показано, как разделить окно приложения на подклассы , чтобы наблюдать за касаниями и перенаправлять эти касания на контроллер представления.
Нет необходимости реализовывать его делегат повсюду в приложении, только там, где я хочу наблюдать нажатия на UIWebView
, так что это может очень хорошо работать для средства просмотра документов.
Пока что я могу наблюдать касания, скрывать и показывать панель инструментов, и UIWebView
ведет себя как веб-представление. Я могу увеличивать и уменьшать масштаб веб-представления, и документ корректно перерисовывается.
Хотя было бы неплохо узнать, как управлять отводами более общим способом, это выглядит довольно неплохим решением.