You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 4中如何无需按钮实现侧边菜单隐藏?

解决Swift 4侧边菜单点击外部自动隐藏的问题

嘿,针对你遇到的侧边菜单需要点击外部区域自动隐藏的需求,这里有两种实用的解决方案,完全适配你的现有代码结构:

方法一:添加全屏点击手势(推荐)

在你的ContainerVC的viewDidLoad中添加一个全屏点击手势,触发时判断侧边菜单状态,同时避免拦截菜单内部的点击事件:

class ContainerVC: UIViewController { 
    @IBOutlet weak var constraint: NSLayoutConstraint! 
    var sideMenuOpen = false 
    
    override func viewDidLoad() { 
        super.viewDidLoad() 
        NotificationCenter.default.addObserver(self, selector: #selector(toggleSideMenu), name: NSNotification.Name("ToggleSideMenu"), object: nil)
        
        // 添加全屏点击手势
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapOutside))
        tapGesture.cancelsTouchesInView = false // 允许底层控件接收触摸事件
        self.view.addGestureRecognizer(tapGesture)
    }
    
    @objc func handleTapOutside(_ gesture: UITapGestureRecognizer) {
        guard sideMenuOpen else { return }
        
        let tapPoint = gesture.location(in: self.view)
        // 替换成你实际的侧边菜单视图(比如从子控制器获取)
        if let sideMenuView = self.childViewControllers.first(where: { $0 is SideMenuVC })?.view {
            if !sideMenuView.frame.contains(tapPoint) {
                toggleSideMenu()
            }
        } else {
            // 找不到菜单视图时直接关闭(可选逻辑)
            toggleSideMenu()
        }
    }
    
    @objc func toggleSideMenu() {
        sideMenuOpen = !sideMenuOpen
        // 根据你的菜单方向调整约束值,这里以左侧菜单为例
        constraint.constant = sideMenuOpen ? 0 : -280 // 280替换成你的菜单实际宽度
        UIView.animate(withDuration: 0.3) {
            self.view.layoutIfNeeded()
        }
    }
}

方法二:重写hitTest拦截触摸事件

通过重写容器控制器的hitTest方法,直接判断触摸点位置,触发关闭逻辑:

class ContainerVC: UIViewController { 
    @IBOutlet weak var constraint: NSLayoutConstraint! 
    var sideMenuOpen = false 
    
    override func viewDidLoad() { 
        super.viewDidLoad() 
        NotificationCenter.default.addObserver(self, selector: #selector(toggleSideMenu), name: NSNotification.Name("ToggleSideMenu"), object: nil)
    }
    
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let touchedView = super.hitTest(point, with: event)
        
        guard sideMenuOpen else { return touchedView }
        
        // 获取侧边菜单视图
        if let sideMenuView = self.childViewControllers.first(where: { $0 is SideMenuVC })?.view {
            if !sideMenuView.frame.contains(point) {
                toggleSideMenu()
                return nil // 让底层视图处理本次触摸
            }
        }
        
        return touchedView
    }
    
    @objc func toggleSideMenu() {
        sideMenuOpen = !sideMenuOpen
        constraint.constant = sideMenuOpen ? 0 : -280
        UIView.animate(withDuration: 0.3) {
            self.view.layoutIfNeeded()
        }
    }
}

关键注意点

  • 确保能正确获取侧边菜单视图:如果是通过添加子控制器的方式实现侧边菜单,用childViewControllers查找对应的SideMenuVC再取view即可。
  • 调整约束数值时,要和你当前菜单的打开/关闭逻辑匹配,右侧菜单可以修改trailing约束。
  • 手势方法中cancelsTouchesInView = false必须设置,否则会拦截其他按钮的点击事件。

内容的提问来源于stack exchange,提问作者chen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:27:07