【问题标题】:Can a UIWebView handle user interaction without becoming first responder?UIWebView 可以在不成为第一响应者的情况下处理用户交互吗?
【发布时间】:2017-02-11 07:05:09
【问题描述】:

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

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

我通过在UITableViewController 上将工具栏视图设置为inputAccessoryView 并将其主要view 设置为第一响应者来实现这一点。主体文本“这是一个链接……”被实现为 UIWebView,因为它填充了来自 Web 服务的 HTML,并且需要支持格式和链接。

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

这是我不想发生的。我需要用户能够点击 Web 视图中的链接,因此不能让它不响应用户交互。

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()
        }
    }

}

谁能告诉我如何以一种简单的方式实现上述目标?

【问题讨论】:

标签: ios swift uiwebview


【解决方案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: 将连接到您的“发布”按钮,并且显然还包含您发布所需的任何其他内容(或者您将其放入 textFieldShouldEndEditing 如果并且在您关闭它之前,即完成输入) . shouldCloseKeyboard 是一个 Bool 变量,它被初始化为 false,但随后使用,如您在此处看到的那样。显然inputField 是您的文本字段(不是整个附件视图!),整个类都符合UITextFieldDelegate,并且文本字段的实例通过接口生成器(或其他方式)设置为delegate

这应该如你所愿。我在一个示例项目中进行了尝试,尽管我没有使用像您这样的工具栏(见下文)或将所有内容放入表格中。我只是做了一个简单的 webview,下面有一个输入和一个关闭东西的按钮。一旦文本字段成为第一响应者,即键盘启动,我可以在 web 视图中单击、点击链接等,并且键盘并没有消失。单击按钮时,它正确关闭(当时我没有打扰什么是第一响应者)。

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

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

因此,从长远来看,我建议您(或任何人)重新考虑将现有视图作为附件进行处理,而是在需要时选择“常规”视图转换,并将附件视图作为“附加助手”。

更新:

好的,我上面描述的(在“快速而肮脏”的解决方案中)假设您只希望 一种方式 退出编辑,即防止 任何其他成为第一响应者,并且只有在按下“完成”后才让它失去第一响应者。

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

class MyWebView: UIWebView {

    public var shouldNotBecomeFirstResponder = false;

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

(我确保如果未设置新的Bool,则会模仿原始行为,这将导致该类在所有其他情况下的行为与 webView 完全相同。不过,我没有在您的设置中进行测试。 ) 显然应该在所有适当的地方设置shouldNotBecomeFirstResponder。例如,我想你可以通过监听键盘(dis)出现通知来做到这一点。

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

所以我#d 使用子类,即使子类几乎没有向 webView 添加任何内容。 :)

【讨论】:

  • 感谢 Gero 的详细回复,我将在下周尝试您的建议。
  • 最初实现这一点时,我确实在是否使用输入附件视图来实现这一点上反复讨论,但除了这个问题之外,它的工作非常可靠(交互式解雇也是一种享受)。根据这个(诚然非常非权威)评论,Apple 在 iOS 消息应用程序stackoverflow.com/questions/24634795/… 中使用了相同的技术@我不愿意重新实现另一种方式。
  • 恐怕这个肮脏的解决方案并不是我真正想要的。如果需要,用户应该能够结束编辑并关闭键盘(以便他们可以在需要时更好地查看下面的内容)。我已经阅读了 Apple 的事件处理指南,但我仍然有点不清楚 UIWebView 必须 是否成为处理链接点击的第一响应者。
  • 我根据您自己对问题的编辑编辑了我的答案。 :)
  • 出于好奇:这解决了你的问题吗,@fractious?
【解决方案2】:

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

[webView endEditing:YES]; 

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-18
    • 2013-03-10
    • 2016-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-26
    • 2021-04-23
    相关资源
    最近更新 更多