iOS Swift4开发:UICollectionView点击弹出透明背景侧边菜单及返回关联问题
嘿,作为Swift开发过来人,我完全懂你这种卡壳的感觉!针对你遇到的侧边菜单问题,我给你一套完整的Swift4实现方案,亲测好用:
解决方案步骤
1. 创建带透明背景的侧边菜单视图控制器
先实现支持点击背景关闭的侧边菜单,核心是设置半透明背景:
import UIKit class SideMenuViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 设置半透明背景(可根据需求调整透明度) view.backgroundColor = UIColor.black.withAlphaComponent(0.5) // 创建左侧菜单内容视图,这里用白色背景举例,你可以自定义样式 let menuContentView = UIView(frame: CGRect(x: 0, y: 0, width: 280, height: view.frame.height)) menuContentView.backgroundColor = .white view.addSubview(menuContentView) // 添加点击背景关闭菜单的手势 let tapBackgroundGesture = UITapGestureRecognizer(target: self, action: #selector(dismissSideMenu)) view.addGestureRecognizer(tapBackgroundGesture) // 让菜单内容区域不响应这个手势,避免误触 menuContentView.isUserInteractionEnabled = true tapBackgroundGesture.cancelsTouchesInView = false } // 关闭菜单的方法 @objc private func dismissSideMenu() { dismiss(animated: true, completion: nil) } }
2. 处理UICollectionView单元格点击事件
在你的CollectionViewController中,实现点击单元格弹出侧边菜单的逻辑:
extension YourCollectionViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // 实例化侧边菜单控制器 let sideMenuVC = SideMenuViewController() // 设置模态弹出样式,确保背景透明显示底层内容 sideMenuVC.modalPresentationStyle = .overCurrentContext // 可选:绑定自定义滑入动画(后面会补充实现) sideMenuVC.transitioningDelegate = self // 弹出菜单 present(sideMenuVC, animated: true, completion: nil) } }
3. 自定义侧边菜单滑入/滑出动画(可选但推荐)
为了让菜单交互更自然,我们可以实现自定义滑入滑出动画,需要遵循UIViewControllerTransitioningDelegate协议:
// 在你的CollectionViewController里扩展实现动画代理 extension YourCollectionViewController: UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return MenuSlideAnimator(isPresenting: true) } func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return MenuSlideAnimator(isPresenting: false) } } // 自定义动画器类 class MenuSlideAnimator: NSObject, UIViewControllerAnimatedTransitioning { private let isPresenting: Bool private let animationDuration: TimeInterval = 0.3 init(isPresenting: Bool) { self.isPresenting = isPresenting super.init() } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return animationDuration } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let toView = transitionContext.view(forKey: .to), let fromView = transitionContext.view(forKey: .from) else { transitionContext.completeTransition(false) return } let container = transitionContext.containerView if isPresenting { // 初始状态:菜单从左侧屏幕外进入 toView.frame = CGRect(x: -toView.frame.width, y: 0, width: toView.frame.width, height: toView.frame.height) container.addSubview(toView) UIView.animate(withDuration: animationDuration) { toView.frame = transitionContext.finalFrame(for: transitionContext.viewController(forKey: .to)!) } _ in transitionContext.completeTransition(true) } } else { // 关闭时:菜单滑回左侧屏幕外 UIView.animate(withDuration: animationDuration) { fromView.frame = CGRect(x: -fromView.frame.width, y: 0, width: fromView.frame.width, height: fromView.frame.height) } _ in transitionContext.completeTransition(true) } } } }
4. 关联导航栏返回按钮逻辑
系统默认返回按钮会直接pop控制器,我们需要自定义返回按钮,让它优先关闭侧边菜单,再执行返回:
class YourCollectionViewController: UICollectionViewController { override func viewDidLoad() { super.viewDidLoad() // 替换系统返回按钮为自定义按钮 let customBackButton = UIBarButtonItem(title: "返回", style: .plain, target: self, action: #selector(handleBackButtonTap)) // 若想保留系统箭头样式,可传入箭头图片: // let customBackButton = UIBarButtonItem(image: UIImage(named: "back_arrow"), style: .plain, target: self, action: #selector(handleBackButtonTap)) navigationItem.leftBarButtonItem = customBackButton } @objc private func handleBackButtonTap() { // 检查当前是否有弹出的侧边菜单 if let presentedVC = presentedViewController, presentedVC is SideMenuViewController { // 先关闭菜单,关闭完成后再返回(不需要返回可去掉completion内代码) dismiss(animated: true) { [weak self] in self?.navigationController?.popViewController(animated: true) } } else { // 无菜单时执行正常返回 navigationController?.popViewController(animated: true) } } }
关键注意事项
- 透明背景生效:必须设置
modalPresentationStyle = .overCurrentContext(iOS13+也可用.overFullScreen),否则系统会自动覆盖背景为黑色。 - 导航栏前提:确保你的CollectionViewController已被推入导航栈,否则导航栏不会显示。
- 手势冲突:若UICollectionView有侧滑手势,需注意与侧边菜单手势区分,避免冲突。
这样一套流程下来,就能完美实现你想要的功能啦!
内容的提问来源于stack exchange,提问作者mmmatey
相关产品推荐
相关产品推荐

