什么可以传递到(并显示所有)子视图?

Ale*_*lds 7 iphone uiwebview uitoolbar uiviewcontroller uiview

我有以下子视图链:

UIViewController.view -+
                       |-> UIView (subclass) -+
                       |                      +-> UIToolbar 
                       |
                       +------------------------> UIWebView
Run Code Online (Sandbox Code Playgroud)

在子类中,我重写其-touchesEnded:forEvent:方法以隐藏和显示UIToolbar单击点击触摸,通过a CAAnimation,以及发出NSNotification导致视图控制器隐藏其导航栏的方法.

如果我不将UIWebView子视图作为子视图添加到视图控制器的视图中,则可以正常工作.

如果我然后添加UIWebView视图控制器的视图的子视图,然后UIToolbar没有出现,我没有得到动画效果.在UIWebView以触摸响应,但子类UIView没有.但是,通知会被触发,导航栏会被隐藏.

安排这些子视图的最佳方法是:

  1. UIToolbar可以使打开和关闭滑动屏幕
  2. 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;
}
Run Code Online (Sandbox Code Playgroud)

该方法-toggleToolbarView:触发NSTimer定时限的CAAnimation隐藏/显示UIToolbar*.

问题是触摸拖动组合导致-toggleToolbarView:被触发(以及放大或缩小Web视图).我想做的是-toggleToolbarView:只有在有触摸事件时才会被解雇.

当我打电话给上面的方法时-hitTest:withEvent:,它看起来很UIWebView糟糕.这两个NSLog报表显示,该UIView*是从返回父UIView*-hitTest:withEvent:要么是UIWebViewUIToolbar(当它在屏幕上摸).该touches数组为空,因此,触摸事件类型不能被区分.

还有一件事我会尝试,但我想在这里记录这个尝试,以防其他人有快速建议.感谢您的继续帮助.


编辑二

我在UIWebView捏/缩放和响应双击方面取得了一些进展.我也可以用单击隐藏/显示工具栏.

而不是搞乱UIWebView实例的私有UIScroller,我访问它的内部私有UIWebDocumentView.但放大后,整个网页视图不会正确重绘.

这意味着:例如,如果我的文档包含PDF或SVG矢量插图,则放大会导致内容模糊,就好像构成渲染的PDF或矢量插图内容的图像切片不会重新渲染一样新的缩放系数.

为了记录这一点,我将:

  1. 调用UIView (subclass),而不是ViewerOverlayView

  2. UIWebView被称为ViewerWebView

两者都是UIView和的子类UIWebView.

我的ViewerWebView包含一个新的ivar(带@property+ @synthesized):

UIView *privateWebDocumentView;
Run Code Online (Sandbox Code Playgroud)

(这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;
}
Run Code Online (Sandbox Code Playgroud)

我的ViewerOverlayView包含新的ivars(带@property+ @synthesized):

ViewerWebView *webView;
UIView *webDocumentView;
Run Code Online (Sandbox Code Playgroud)

在覆盖视图的实现中,我重写-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];
}
Run Code Online (Sandbox Code Playgroud)

在视图控制器中,我执行以下操作:

  1. 实例化ViewerOverlayView并将其添加为视图控制器view属性的子视图

  2. 实例化视图控制器的ViewerWebView实例并将其插入子视图数组的底部

  3. ViewerOverlayViewWeb视图属性设置为视图控制器的Web视图

所以现在我的透明ViewerOverlayView正确地将缩放/拉伸/双击触摸事件传递给ViewerWebView实例的私有UIWebDocumentView实例.在UIWebDocumentView随后调整大小.

但是,内容不会使用新比例重绘.因此,基于矢量的内容(例如PDF,SVG)在放大时看起来很模糊.

这是视图看起来没有缩放,漂亮和锐利的样子:

UIWebView,无缩放

以下是放大时视图的样子,如果没有所有这些自定义事件的话,它就不会像以前那样清晰:

UIWebView,模糊缩放

有趣的是,我只能在两个缩放级别之间重新缩放.一旦我停止双击拉伸以放大任何级别,它就会"快速回退"到您在上图中看到的帧.

我尝试-setNeedsDisplayViewerWebView它的内部UIWebDocumentView实例.两种方法调用都不起作用.

尽管想要避免私有方法,因为我想最终获得批准的应用程序,我也尝试了访问私有方法的这个建议:UIWebDocumentView-_webCoreNeedsDisplay

[(UIWebDocumentView *)self.webDocumentView _webCoreNeedsDisplay];
Run Code Online (Sandbox Code Playgroud)

此方法导致应用程序从unrecognized selector异常中崩溃.也许Apple已将此方法的名称从SDK 3.0更改为3.1.2.

除非有办法让Web视图重绘其内容,否则我想我将不得不废弃透明覆盖视图并只绘制Web视图,以使Web视图正常工作.太糟糕了!

如果有人有关于重绘后缩放的想法,请随时添加答案.

再次感谢大家的投入.顺便说一句,我没有取消对这个问题的赏金 - 我不知道为什么它没有自动被授予这个帖子的第一个答案,因为我原本期望从以前的经验中发生.


编辑III

我发现这个网页显示了如何子类化应用程序窗口,以便观察点击并将这些点击转发到视图控制器.

没有必要在整个应用程序中的任何地方实现其委托,只有在我想要观察点击的地方UIWebView,所以这对于文档查看器可能非常有效.

到目前为止,我可以观察点击,隐藏和显示工具栏,并且UIWebView行为类似于Web视图.我可以放大和缩小Web视图,并正确地重新呈现文档.

虽然学习如何以更通用的方式管理水龙头会很好,但这看起来是一个非常好的解决方案.

ohh*_*rob 3

我阅读您问题的方式是,您希望拦截事件以触发某些操作(动画工具栏、发布通知),同时允许事件也到达其自然目的地。

如果我尝试这样做,我会UIToolbar直接将 放置为 的子视图UIViewController.view。它UIWebView仍然是一个直接子视图。

应该UIViewController.view是 的子类UIView,并且需要重写

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
Run Code Online (Sandbox Code Playgroud)

视图可以通过发回您想要接收事件的视图(UIToolbar 或 UIWebView)来回避成为事件处理的一部分,同时您仍然有机会触发您想要的操作。

一个例子可能是:

- (UIView *)hitTest:(CGPoint) point withEvent:(UIEvent *)event {
    UIView* subview = [super hitTest:point withEvent:event];
    /* Use the event.type, subview to decide what actions to perform */
    // Optionally nominate a default event recipient if your view is not completely covered by subviews
    if (subview == self) return self.webViewOutlet;
    return subview;
}
Run Code Online (Sandbox Code Playgroud)