UIWebView能否在不成为第一响应者的情况下处理用户交互?

时间:2016-10-03 10:50:51

标签: ios swift uiwebview

我的应用程序有类似于iOS消息应用程序的视图,工具栏样式视图包含停靠在屏幕底部的文本字段:

当用户点击文本字段以输入文本时,键盘会向上滑动,工具栏会随之滑动:

我已通过在inputAccessoryView上将工具栏视图设为UITableViewController并使其主view成为第一响应者来实现此目的。主体文字"这是一个链接..."实现为UIWebView,因为它填充了来自Web服务的HTML,需要支持格式和链接。

我遇到的问题是,当用户点按UIWebView上的任意位置时,它会成为第一响应者而inputAccessoryView隐藏自己:

我不想发生这种事。我需要用户能够点按网络视图中的链接,这样就不会对用户互动做出响应。

UIWebView 是否成为处理点按的第一响应者?如果是这样,webview是否可以处理链接上的点击,但是然后将触摸事件传递给主view并立即再次制作第一个响应者?任何有关如何解决这个问题的指示都将非常感激。

更新

因此,网页视图似乎没有 成为处理链接点击的第一响应者,因为我可以通过以下方式解决问题:

extension UIView {

    public override func becomeFirstResponder() -> Bool {
        // Actual view is instance of private class UIWebBrowserView, its parent parent view is UIWebView
        if self.superview?.superview is UIWebView {
            return false
        } else {
            return super.becomeFirstResponder()
        }
    }

}

谁能告诉我如何以非黑客的方式实现上述目标?

2 个答案:

答案 0 :(得分:1)

我可以在这里提供两件事。一个快速而肮脏的解决方案(我希望)和建议(或者你可能会称之为惊讶)。

肮脏的解决方案:实现类似的东西

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    self.shouldCloseKeyboard = false
    return true
}

func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
    return self.shouldCloseKeyboard
}

@IBAction func inputDone(_ sender: AnyObject) {
    if self.inputField.isFirstResponder {
        self.shouldCloseKeyboard = true
        self.inputField.resignFirstResponder()
    }
}

inputDone:将与您的" Post"相关联。按钮,显然还包含你需要做的任何其他发布(或者你把它放在textFieldShouldEndEditing中,如果和之前关闭它,即完成输入)。 shouldCloseKeyboardBool var,其初始化为false,但随后会在此处使用。显然inputField是你的文本字段(不是整个附件视图!),整个类符合UITextFieldDelegate,文本字段的实例通过Interface Builder设置为delegate(或其他方式)。

这应该按照您的意图行事。我在一个示例项目中尝试过,虽然我没有使用像你这样的工具栏(见下文)或将所有内容放入表中。我只是做了一个简单的webview,下面有一个输入和一个关闭东西的按钮。一旦文本字段是第一个响应者,即键盘已启动,我可以单击webview,按照链接等,键盘也不会消失。单击按钮时,它正确关闭(我没有打扰当时的第一响应者)。

现在让我感到惊讶的是:起初我觉得把它简单地用作inputAccessoryView工具栏让它在键盘上移动是一个很好的技巧。然而,进一步的想法我得出结论我不会这样做(而是在键盘显示时手动移动视图,以及其他任何东西。你可能也必须这样做,以确保没有重要的是被键盘或配件视图遮挡)。原因是附件视图不应该在其他地方的视图层次结构中。事实上,当我在我的演示项目中快速尝试它时(我在UIView中嵌入了按钮和文本字段,为此定义了一个插座,然后将其设置为inputAccessoryView in代码,尝试在各个地方)应用程序崩溃。这是合理的,因为textfield本身是容器的子视图,它可能是附件,但同时也是视图控制器主视图的一个孩子...我很惊讶你设法克服了这一切

简而言之,这种做法似乎很麻烦。我理解输入附件视图的方式,更多意味着用于其他视图,而不是用于已经在屏幕上显示的控件(因此已经是视图层次结构的一部分)。在另一个项目中,我特别避免通过简单地伪装它来搞乱这个:我有一个单独的视图作为附件加载,看起来就像控制它"关联"用。一旦显示了这个假视图,我就将第一个响应者切换到它(好吧,它的一个子视图,一个文本字段,所以键盘保持不动),我的用户可以编辑。按下完成按钮后,我将输入复制到"原始"文本字段,所有都是neato。

因此,从长远来看,我会建议您(或任何人)重新考虑将现有观点视为附件,而是选择"常规"在需要的地方查看转移并继续使用附件视图作为"其他帮助者"。

<强>更新

好的,我上面所描述的(在#34;快速和肮脏的&#34;解决方案中)假设你只想要编辑的一个出路,即阻止任何事情< / em> else成为第一响应者,只让它失去第一响应者一次&#34;完成&#34;被按下了。

关于webView,它完成了同样的事情。尝试阻止 webView 成为第一响应者时的问题是如何识别导致文本字段失去第一响应者状态的原因。我认为你的&#34; hacky&#34;接近指向正确的方向,但由于你不应该覆盖扩展中的方法(iirc),我建议在这种情况下继承UIWebView。然后你也可以给它一个属性打开和关闭该行为(即如果文本字段成为第一响应者/开始编辑你打开它,一旦它失去它你关闭它)。对于子类来说,这应该足够了:

class MyWebView: UIWebView {

    public var shouldNotBecomeFirstResponder = false;

    override public var canBecomeFirstResponder: Bool {
        if self.shouldNotBecomeFirstResponder {
            return false
        } else {
            return super.canBecomeFirstResponder
        }
    }
}

(如果没有设置新的Bool,我确保模仿原始行为,这会导致Class在所有其他情况下的行为与webView完全相同。我没有在你的测试中做到这一点虽然安装。) 显然应该在所有适当的地方设置shouldNotBecomeFirstResponder。我想你可以这样做,例如听取键盘(dis)外观通知。

通常,可能还有其他方法可以做到这一点,不需要子类。除了我上面的第一个建议之外,您还可以使用手势识别器来确定是否必须设置shouldCloseKeyboard,但这可能更多的工作并导致难以阅读/维护代码。可能很难弄清楚首先调用的是什么,算法是否点击了webView(因此shouldCloseKeyboard必须在之前设置它实际上成为第一响应者!)或其他东西(在这种情况下,它必须以某种方式取消)。

所以我继续使用子类化,即使子类几乎没有为webView添加任何内容。 :)

答案 1 :(得分:0)

我的情况完全一样,这是我的解决方案:

[webView endEditing:YES]; 

当用户点击文本字段以输入文本时,可以调用此方法。