iphone - 什么可以将触摸传递到(并显示所有) subview ?

标签 iphone uiview uiviewcontroller uiwebview uitoolbar

我有以下 subview 链:

UIViewController.view -+
                       |-> UIView (subclass) -+
                       |                      +-> UIToolbar 
                       |
                       +------------------------> UIWebView

在子类中,我覆盖了它的 -touchesEnded:forEvent:方法来隐藏和显示 UIToolbar只需轻轻一按,即可通过 CAAnimation ,以及发出 NSNotification这会导致 View Controller 隐藏其导航栏。

如果我不添加 UIWebView作为 View Controller View 的 subview ,那么这可以正常工作。

如果我再添加 UIWebView作为 View Controller View 的 subview ,然后是 UIToolbar没有出现,我也没有得到动画效果。 UIWebView响应触摸但子类 UIView才不是。但是,通知确实被触发了,并且导航栏确实被隐藏了。

安排这些 subview 的最佳方法是什么,以便:
  • UIToolbar可以在屏幕上下滑动
  • UIWebView is visible 仍然可以接收其典型的触摸事件:放大/缩小和双击以重置缩放级别

  • 正确答案将满足这两个标准。

    编辑

    我在这方面取得了一些进展,但我无法区分触摸事件,因此我在不应该触发时触发了工具栏隐藏/显示方法。

    我将 View Controller 的 view 属性设置为 UIView子类,我在 -subviews 的顶部插入了 web View 阵列通过 [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:被触发(以及放大或缩小 WebView )。我想做的是事业-toggleToolbarView:仅在有仅触摸事件时触发。

    当我调用上述方法时 -hitTest:withEvent: ,看起来像 UIWebView吸收接触。两人NSLog声明显示UIView*这是从父项 UIView* 返回的的 -hitTest:withEvent:要么是 UIWebViewUIToolbar (当它在屏幕上并被触摸时)。 touches数组为空,因此无法区分触摸事件类型。

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

    编辑二

    我在获得 UIWebView 方面取得了一些进展捏/缩放和响应双击。我还可以通过单击隐藏/显示工具栏。

    而不是搞乱 UIWebView实例的私有(private) UIScroller ,我访问它的内部,私有(private) UIWebDocumentView .但是整个 WebView 在放大后无法正确重绘。

    这意味着:如果我的文档包含 PDF 或 SVG 矢量图,例如,放大会导致内容模糊,就好像构成渲染的 PDF 或矢量图内容的图像块没有被重新渲染新的缩放系数。

    为了记录这一点,我将:
  • 调用 UIView (subclass)相反 ViewerOverlayView
  • UIWebView被称为 ViewerWebView

  • 两者都是 UIView 的子类和 UIWebView , 分别。

    我的 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;
    }
    

    我的 ViewerOverlayView包含新的 ivars(带有 @property + @synthesized):
    ViewerWebView *webView;
    UIView *webDocumentView;
    

    在覆盖 View 的实现中,我覆盖了 -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];
    }
    

    在 View Controller 中,我执行以下操作:
  • 实例化 ViewerOverlayView并将其添加为 View Controller view 的 subview 属性(property)
  • 实例化 View Controller 的 ViewerWebView实例并将其插入 subview 数组的底部
  • 设置 ViewerOverlayView View Controller 的 web View 的 web View 属性

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

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

    这是没有缩放的 View ,漂亮而清晰:

    UIWebView, no scaling

    这是放大时 View 的样子,它不像没有所有这些自定义事件处理那样清晰:

    UIWebView, blurry zoom

    有趣的是,我只能在两个缩放级别之间重新缩放。一旦我停止双击拉伸(stretch)以放大任何级别,它就会“回弹”到您在上图中看到的框架。

    我试过 -setNeedsDisplayViewerWebView及其内部 UIWebDocumentView实例。两种方法调用都不起作用。

    尽管想避免使用私有(private)方法,但因为我想最终让这个应用获得批准,我也尝试了 this suggestion访问私有(private) UIWebDocumentView方法 -_webCoreNeedsDisplay :
    [(UIWebDocumentView *)self.webDocumentView _webCoreNeedsDisplay];
    

    此方法导致应用程序从 unrecognized selector 崩溃异常(exception)。也许苹果已经将这个方法的名称从 SDK 3.0 更改为 3.1.2。

    除非有办法让 web View 重绘其内容,否则我想我将不得不废弃透明覆盖 View 并只绘制一个 web View ,以便让 web View 正常工作。真糟糕!

    如果有人对缩放后重绘有任何想法,请随时添加答案。

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

    编辑三

    我发现这个网页显示 how to subclass the application window以便观察点击并将这些点击转发到 View Controller 。

    没有必要在整个应用程序的任何地方实现它的委托(delegate),只有在我想观察 UIWebView 上的点击的地方才需要实现。 ,因此这对于文档查看器可能非常有效。

    到目前为止,我可以观察点击、隐藏和显示工具栏,以及 UIWebView表现得像一个 WebView 。我可以放大和缩小 Web View ,并且可以正确重新渲染文档。

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

    最佳答案

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

    如果我尝试这样做,我会放 UIToolbar直接作为UIViewController.view的 subview . UIWebView仍然是一个直接的 subview 。
    UIViewController.view应该是 UIView 的子类,它需要覆盖

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    

    View 可以通过发送回您想要接收事件的 View (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;
    }
    

    关于iphone - 什么可以将触摸传递到(并显示所有) subview ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1856411/

    相关文章:

    iphone - 如何在没有 Interface Builder 的情况下在 UIViewController 中实现 UISearchDisplayController

    ios - 我应该只对多行页面使用 TableView 吗?

    iphone - UITableView 编辑/完成按钮

    iphone - 如何删除以编程方式添加的自定义 View ?

    objective-c - 在重叠动画 block 中设置 UIView 的 frame 属性导致跳转

    iphone - 将表格 View 和导航控件添加到现有基于 View 的应用程序

    iphone - 添加到可变数组的对象数量不正确

    iPhone 图片幻灯片

    ios - 在父 UIView 中移动 UIView (UIPanGestureRecognizer)

    ios - 排队的 ViewControllers 被一个接一个地推送