次のサブビュー チェーンがあります。
UIViewController.view -+
|-> UIView (subclass) -+
| +-> UIToolbar
|
+------------------------> UIWebView
サブクラスでは、ビュー コントローラーがナビゲーション バーを非表示にする を発行するだけでなく、 を介してシングル タップ タッチで-touchesEnded:forEvent:
を表示および非表示にするために、そのメソッドをオーバーライドします。UIToolbar
CAAnimation
NSNotification
UIWebView
View Controllerのビューにサブビューとして追加しないと、これは正しく機能します。
UIWebView
次に、ビュー コントローラーのビューのサブビューとしてを追加すると、 が表示されUIToolbar
ず、アニメーション効果が得られません。はUIWebView
タッチに応答しますが、サブクラスは応答しUIView
ません。ただし、通知は発生し、ナビゲーション バーは非表示になります。
これらのサブビューを次のように配置する最良の方法は何ですか?
UIToolbar
を画面上または画面外にスライドさせることができます- 表示され
UIWebView
ている は、通常のタッチ イベントを受け取ることができます: ズームイン/ズームアウト、ダブルタップしてズーム レベルをリセットします。
正解は両方の基準を満たします。
編集
これである程度の進歩はありましたが、タッチイベントを区別できないため、ツールバーの非表示/表示メソッドを起動してはならないときに起動します。
ビュー コントローラーのビュー プロパティをUIView
サブクラスに設定し、.-subviews
経由で配列の先頭に Web ビューを挿入しました[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;
}
このメソッドは、 を非表示/表示する-timedを-toggleToolbarView:
トリガーします。NSTimer
CAAnimation
UIToolbar*
問題は、タッチとドラッグの組み合わせが発生-toggleToolbarView:
することです (および Web ビューのズームインまたはズームアウト)。私がやりたいの-toggleToolbarView:
は、タッチのみのイベントがある場合にのみ発生させることです。
上記のメソッドを呼び出すと、タッチを吸う-hitTest:withEvent:
ように見えます。UIWebView
2 つのステートメントNSLog
はUIView*
、親から返される がまたは(画面上でタッチされている場合) であることを示しています。配列が空であるため、タッチ イベントの種類を区別できません。UIView*
-hitTest:withEvent:
UIWebView
UIToolbar
touches
もう 1 つ試してみたいことがありますが、他の人からの簡単な提案がある場合に備えて、この試みをここに記録しておきます。いつもお世話になっております。
編集Ⅱ
UIWebView
ピンチ/ズームとダブルタップへの応答を取得することで、いくつかの進歩がありました。シングルタップでツールバーを非表示/表示することもできます。
UIWebView
インスタンスの privateをいじる代わりに、UIScroller
その内部の private にアクセスしますUIWebDocumentView
。ただし、ズームインした後、Web ビュー全体が適切に再描画されません。
これが意味すること: たとえば、ドキュメントに PDF または SVG ベクター イラストが含まれている場合、レンダリングされた PDF またはベクター イラスト コンテンツを構成する画像タイルが再レンダリングされていないかのように、拡大するとコンテンツがぼやけます。新しいズーム倍率。
これを文書化する目的で、私は次のことを行います。
代わり
UIView (subclass)
にViewerOverlayView
と
UIWebView
呼ばれるViewerWebView
どちらもそれぞれUIView
とのサブクラスUIWebView
です。
MyViewerWebView
には新しい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;
}
MyViewerOverlayView
には新しいivarが含まれています(@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 Controller のview
プロパティのサブビューとして追加しますビューコントローラーの
ViewerWebView
インスタンスをインスタンス化し、サブビュー配列の一番下に挿入しますViewerOverlayView
Web ビュー プロパティをビュー コントローラーの Web ビューに設定します。
これで、トランスペアレントViewerOverlayView
はズーム/ストレッチ/ダブルタップ タッチ イベントをViewerWebView
インスタンスのプライベートUIWebDocumentView
インスタンスに正しく渡します。その後UIWebDocumentView
、サイズが変更されます。
ただし、コンテンツは新しいスケールで再描画されません。そのため、ベクターベースのコンテンツ (PDF、SVG など) は、拡大するとぼやけて見えます。
スケーリングなしのビューは次のようになります。素晴らしくシャープです。
ズームインしたときのビューは次のようになります。これは、このすべてのカスタム イベント変更がない場合ほど鮮明ではありません。
興味深いことに、2 つのズーム レベル間でのみ再スケーリングできます。任意のレベルでズームインするためにダブルタップストレッチを停止すると、上の画像に表示されているフレームに「スナップバック」します。
とその内部インスタンスを試し-setNeedsDisplay
ました。どちらのメソッド呼び出しも機能しませんでした。ViewerWebView
UIWebDocumentView
プライベート メソッドを避けたいにもかかわらず、最終的にはこのアプリを承認してもらいたいので、プライベートメソッドへのアクセスに関する次の提案も試しました。UIWebDocumentView
-_webCoreNeedsDisplay
[(UIWebDocumentView *)self.webDocumentView _webCoreNeedsDisplay];
unrecognized selector
このメソッドにより、アプリが例外からクラッシュしました。おそらく、Apple はこのメソッドの名前を SDK 3.0 から 3.1.2 に変更しました。
Web ビューのコンテンツを再描画する方法がない限り、Web ビューを適切に機能させるには、透明なオーバーレイ ビューを破棄して Web ビューを描画する必要があると思います。それは最悪です!
スケーリング後の再描画について誰かが考えている場合は、お気軽に回答を追加してください。
ご意見をお寄せいただきありがとうございました。余談ですが、私はこの質問の報奨金をキャンセルしませんでした。以前の経験から予想していたように、このスレッドへの最初の回答に賞金が自動的に授与されなかった理由はわかりません。
編集Ⅲ
アプリケーションウィンドウをサブクラス化してタップを監視し、それらのタップをView Controllerに転送する方法を示すこのWebページを見つけました。
アプリケーション全体のどこにでもデリゲートを実装する必要はなく、 のタップを観察したい場所にのみ実装する必要があるUIWebView
ため、これはドキュメント ビューアーにとって非常にうまく機能する可能性があります。
これまでのところ、タップを観察したり、ツールバーを非表示および表示したりUIWebView
、Web ビューのように動作したりできます。Web ビューをズームインおよびズームアウトでき、ドキュメントは適切に再レンダリングされます。
より一般的な方法でタップを管理する方法を学ぶのは良いことですが、これは非常に優れたソリューションのように見えます.