在iOS工程中,通常咱们的概况页面UI都是比较复杂的,这就导致往往视图层级较深,这种情况下,假如要将内部的UIView识别到事情时,抛出到VC来履行详细处理,需求一层一层中转,很费事。

本文是介绍一种处理一层一层中转直达VC的方式。

一、问题引出

如下是一个打车软件的概况截图。咱们剖析页面,打赏司机按钮的层级结构: UIButton -》ZLToolView -》ZLHeaderView -》UITableView -》ZLContentView -》VC.view -》 VC。

iOS中将UIView事件跨层传递给VC

现在,假如咱们点击打赏司机,需求VC去履行逻辑。

1. 不管是运用署理或许block,这个链路都很长。

这个事情首先是在ZLToolView增加按钮点击监听,然后需求中转回调给ZLHeaderView, 再回调给UITableView的父视图ZLContentView, 最终再回调给VC。

2. 运用大局告诉

假如运用告诉的话,能做到跨层,可是缺陷是告诉更适合于大局的一对多场景,一个UI事情还是1对1的关系; 此外过多的告诉也不利于维护。

二、处理方案

上述问题我这边考虑的一个处理方案是经过响应者链来完成从内层的View事情跨层抛给VC,理由如下:

  • 响应者链在UIView增加到Superview上之后就存在,不必自己额定再建立责任链(响应者链其实是一个责任链规划模式)。
  • 经过响应链来传递能够使得链中任何关心这个事情的上级可拦截。
  • 完成的是1对1的响应。

详细的封装代码如下:

// 事情需求根据需求去扩展
enum XLInnerViewEvent {
    case refreshABC // 改写ABC
    case refreshDetail // 改写概况接口,假如有参数,能够经过枚举相关值传递
}
protocol XLInnerEventResponsible: UIResponder {
    func innerEventHandle(type: XLInnerViewEvent)
}
extension UIView {
    // 一个沿着响应链向上传递事情的方法,bubble=冒泡
    func bubbleEvent(_ eventType: XLInnerViewEvent) {
        var nextRespnder = self.next
        while nextRespnder != nil {
            if let savior = nextRespnder as? XLInnerEventResponsible {
                savior.innerEventHandle(type: eventType)
                nextRespnder = nil
            }
            nextRespnder = nextRespnder?.next
        }
     }
}

运用:

// 内层view传递事情
@objc func reloadBtnAction() {
    self.bubbleEvent(.refreshABC)
}
// VC或响应链中感兴趣的类遵守协议XLInnerEventResponsible
extension VC: XLInnerEventResponsible {
    func innerEventHandle(type: XLInnerViewEvent) {
        switch type {
        case .refreshABC:
            print("refreshABC---")
        case .refreshDetail:
            print("refreshDetail---")
        }
    }
}