今天小编给大家分享一下ios响应链的工作原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
在 iOS
中,事件响应链的工作原理可以简单概括为:从最上层的 UIWindow 开始,依次向下传递事件,直到找到最适合处理事件的响应者对象为止。在这个过程中,每个响应者对象都有机会处理事件。
当用户执行一个操作时,如触摸屏幕或运动设备,系统会创建一个 UIEvent 对象,并将其发送到当前的第一响应者对象。如果第一响应者对象无法处理该事件,则系统会将该事件传递给响应者链中的下一个对象,直到找到能够处理该事件的对象。如果最终没有对象能够处理该事件,则事件被系统丢弃。
以下是事件响应链的示意图:
UIWindow | UIViewController | UIView | subviews of UIView
在这个示意图中,UIWindow
是响应者链的起点,它是所有视图的根视图。UIViewController
和 UIView
都是响应者对象,它们都可以处理事件。UIViewController
可以接收和处理来自其根视图的事件,而 UIView
可以接收和处理来自其自身的事件,以及来自其子视图的事件。
响应者对象是一种特殊类型的对象,它们实现了 UIResponder
类。响应者对象可以处理事件,可以成为第一响应者对象,并且可以将事件传递给下一个响应者对象。以下是 UIResponder
类中的一些常用方法:
canBecomeFirstResponder
:返回一个布尔值,指示对象是否可以成为第一响应者对象。
becomeFirstResponder
:将对象设置为第一响应者对象。
resignFirstResponder
:放弃第一响应者对象的地位。
next
:返回响应者链中的下一个响应者对象。
响应者对象还可以实现许多方法来处理事件,例如:
touchesBegan(_:with:)
:当用户在视图上开始触摸时调用。
touchesMoved(_:with:)
:当用户在视图上移动触摸时调用。
touchesEnded(_:with:)
:当用户在视图上结束触摸时调用。
touchesCancelled(_:with:)
:当系统取消触摸事件时调用。
在 Swift
中,可以通过重写 UIResponder
子类的方法来自定义事件处理。以下是一个示例代码,展示如何重写 UIView
子类的 touchesBegan
方法来处理触摸事件:
class CustomView: UIView { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) // 处理触摸事件 // ... } }
在这个示例中,当用户在 CustomView
上开始触摸时,系统会调用 CustomView
的 touchesBegan
方法。在此方法中,开发者可以编写自己的触摸事件处理代码。
事件传递和事件响应是事件响应链的两个重要环节。在事件传递阶段,系统会将事件从上往下传递,直到找到最适合处理事件的对象。在事件响应阶段,系统会将事件从下往上响应,直到事件被处理或者传递到响应者链的顶部。
在事件传递阶段,UIView
和 UIViewController
都有一个 hitTest( *:with:)
方法,该方法返回一个 UIView
对象。当系统接收到事件时,它会调用 hitTest(* :with:)
方法来确定最适合处理该事件的视图对象。hitTest( *:with:)
方法首先检查自己是否能够处理该事件,如果不能,它会将事件传递给其子视图,并递归调用子视图的 hitTest(* :with:)
方法,直到找到能够处理该事件的视图对象。
在事件响应阶段,系统会将事件传递到第一响应者对象,并沿着响应者链向上传递,直到事件被处理或者传递到响应者链的顶部。在这个过程中,每个响应者对象都有机会处理事件。如果某个响应者对象能够处理事件,则它将调用相应的方法来处理事件,例如 touchesBegan(_:with:)
方法。如果该对象不能处理事件,则它将调用 next
方法,将事件传递给响应者链中的下一个对象。
在 hitTest(_:with:)
方法中,我们可以检查触摸点是否在指定区域内,如果在,则返回当前视图作为拦截目标,否则返回 nil
,让系统将事件传递给下一个响应者。示例代码如下:
class CustomView: UIView { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { if self.bounds.contains(point) { // 触摸点在视图内,拦截事件 return self } else { // 触摸点不在视图内,将事件传递给下一个响应者 return super.hitTest(point, with: event) } } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) print("CustomView touchesBegan") } }
在上述代码中,我们重写了 hitTest( *:with:)
方法,并在该方法中检查触摸点是否在视图内。如果在,则返回当前视图作为拦截目标,否则返回 nil,让系统将事件传递给下一个响应者。在 touchesBegan(* :with:)
方法中,我们打印了一条日志,以便在触摸事件发生时能够看到该方法是否被调用。
要将事件传递到父视图,可以调用 next?.touchesBegan(touches, with: event)
方法,让父视图处理触摸事件。示例代码如下:
class CustomView: UIView { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) // 处理触摸事件 // 如果无法处理该事件,传递给父视图进行处理 next?.touchesBegan(touches, with: event) } } class ParentView: UIView { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) // 处理触摸事件 } }
在上面的示例中,CustomView
和 ParentView
都是 UIView
的子类。当用户在 CustomView
上触摸时,CustomView
的 touchesBegan
方法会被调用。在这个方法中,如果 CustomView
无法处理该事件,它会将该事件传递给其父视图(ParentView
)进行处理。
通过 next?.touchesBegan(touches, with: event)
方法将事件传递给父视图,如果父视图能够处理该事件,它的 touchesBegan
方法将被调用。在这个方法中,可以处理触摸事件。如果父视图仍然无法处理该事件,该事件将被传递给更高级别的响应对象进行处理。
需要注意的是,当事件被传递到下一个响应对象时,会调用该对象的 touchesBegan
方法。因此,在这个方法中,可以对事件进行处理,也可以将其传递给更高级别的响应对象进行处理。
在 iOS
中,每个视图都是一个 UIResponder
对象。UIResponder
是一个抽象类,它定义了响应者对象可以处理的事件类型,包括触摸事件、加速计事件、远程控制事件等。每个 UIResponder
对象都有一个 next
响应者,即下一个响应者对象。当一个事件发生时,系统会将该事件从前往后依次传递给响应者链中的对象,直到某个对象处理了该事件为止。如果没有任何对象处理该事件,则该事件将被丢弃。
我们可以通过自定义 UIResponder
子类来实现更灵活的事件处理逻辑。下面是一个简单的自定义响应者链的示例代码:
class CustomResponder: UIResponder { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) print("CustomResponder touchesBegan") next?.touchesBegan(touches, with: event) } } class ViewController: UIViewController { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) print("ViewController touchesBegan") } }
在上面的代码中,我们定义了一个名为 CustomResponder
的自定义响应者子类。在该类中,我们重写了 touchesBegan(_:with:)
方法,并在该方法中打印了一条日志。在该方法中,我们还调用了 next?.touchesBegan(touches, with: event)
方法,将触摸事件传递给下一个响应者对象。
在 ViewController 中,我们也重写了 touchesBegan( *:with:)
方法,并在该方法中打印了一条日志。当触摸事件发生时,首先会调用 CustomResponder
的 touchesBegan(* :with:)
方法,并打印出 "CustomResponder touchesBegan
"。然后,由于我们调用了 next?.touchesBegan(touches, with: event)
方法,系统会将触摸事件传递给 CustomResponder
的下一个响应者对象,即 ViewController
。此时,系统会调用 ViewController
的 touchesBegan(_:with:)
方法,并打印出 "ViewController touchesBegan
"。
通过自定义响应者子类,我们可以更加灵活地处理事件,实现更复杂的事件处理逻辑。例如,我们可以在响应者链中添加多个响应者对象,根据事件类型、触摸点位置等条件来决定哪个响应者对象处理该事件。
以上就是“ios响应链的工作原理是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。