【问题标题】:Missing First Responder in iOS 11 with Swift 4 App (Xcode 9.X)?在带有 Swift 4 应用程序 (Xcode 9.X) 的 iOS 11 中缺少第一响应者?
【发布时间】:2018-08-03 20:15:50
【问题描述】:

我有一个精简的、基于代码的测试应用程序(不是Storyboard),它有:

  • UIWindow对象
  • ViewController,及其主视图
  • 顶部有一个UIView 对象。 -

为了测试哪个对象是第一响应者,我在 tochesBegan 中评估,在 topView 内如下,但所有项目都响应 false。响应链正在工作,因为检测到触摸(在 topView 和主控制器的视图中。

这是应用程序的精简版。鉴于这不是一个简单的视图-子视图层次结构,我不使用递归函数。

import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow()
        window?.rootViewController = ViewController()
        window?.makeKeyAndVisible()
        return true
    }
}
class ViewController: UIViewController {
    override func viewDidLoad() {
        let topView = View()
        self.view.addSubview(topView)
    }
}
class View: UIView {
    convenience init() {
        self.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        self.backgroundColor = UIColor.yellow
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let window = (UIApplication.shared).delegate?.window as? UIWindow
        let viewController = window?.rootViewController
        let mainView = viewController?.view
        print("Window?: \(window!.isFirstResponder)")
        print("View Controller?: \(viewController!.isFirstResponder)")
        print("Main View?: \(mainView!.isFirstResponder)")
        for view in (mainView?.subviews)! {
            print("Any View?: \(view.isFirstResponder)")
        }
    }
}

所有评估都返回 false。我在这里做错了吗?

问候... e

【问题讨论】:

    标签: ios swift uiresponder


    【解决方案1】:

    我相信如果没有子类化,很少有视图对象(UITextField、UITextView)可以成为第一响应者,最好检查一下UIViewcanBecomeFirstResponder

    如果你想实现这个功能,比如高亮,选择一个UIView,你必须继承UIView并覆盖becomeFirstResponder,如下:

    class CustomView: UIView {
    
        override var isFirstResponder: Bool {
            return true
        }
    
    }
    

    要进行上述测试,请在您的 ViewController 中添加以下内容:

    override func loadView() {
        self.view = CustomView()
    }
    

    现在检查我们的 CustomView 是否是FirstResponder:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("View: \(self.view.isFirstResponder)")
    }
    

    【讨论】:

    • 谢谢@AamirR,我学到了一些新东西。使用 UITextView 代替 UIView 有效。不是所有的观点都可以成为 firstResponder 有点矛盾。请参阅:了解事件处理、响应者和响应者链 - 对于每种类型的事件,UIKit 都会指定一个第一响应者并首先将事件发送到该对象。第一响应者因事件类型而异。触摸事件第一响应者是发生触摸的视图developer.apple.com/documentation/uikit/…
    • 你看class CustomView: UIView的例子,开箱即用(没有子类化)只有少数视图对象(UITextField,UITextView)可以成为第一响应者,你仍然可以使UIView或UILabel成为第一响应者,您只需要子类化视图并覆​​盖属性。不是很矛盾,是吗?
    • 如果没有子类化,则基本 UIView 类(或 UILabel 等...)无法告诉您它是第一响应者,不客气,也感谢您的这篇文章))
    【解决方案2】:

    我认为从一开始就没有第一响应者。您仍然可以接收到您的视图的事件。

    响应者对象
    鼠标事件和多点触控事件首先进入下的视图 鼠标指针或手指;这种观点可能是也可能不是第一个 响应者。

    More on responders

    nextResponder
    UIResponder 类不存储或设置下一个响应者 自动,所以这个方法默认返回 nil。

    More on nextResponder

    【讨论】:

    • 谢谢@LGP,你是对的。文档似乎是矛盾的...developer.apple.com/documentation/uikit/… - 了解事件处理、响应者和响应者链 - 确定事件的第一响应者 对于每种类型的事件,UIKit 指定一个第一响应者并将事件发送到该对象第一的。第一响应者因事件类型而异。触摸事件 第一响应者是发生触摸的视图。
    • 是的,有趣的是,链接上写着There is no single responder chain within your app. UIKit defines default rules for how objects are passed from one responder to the next, but you can always change those rules by overriding the appropriate properties in your responder objects. 链似乎更像是一种遍历算法,只有一个指向当前firstResponder 的指针——如果有的话。此外,firstResponder 似乎只用于键盘事件,因为点击会转到点击下方的视图。
    猜你喜欢
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多