Swift:登录场景下触发自定义Alert时如何避免视图重叠问题
问题原因
你遇到的弹窗重叠问题来自两个核心逻辑漏洞:
- 每次调用
showAlert方法时,都会向全局复用的alertView上新增标题、文本、按钮三个子视图,但dismiss时仅移除了alertView本身,没有清理其内部的旧子视图,多次调用后子视图堆叠就会出现文字重影 - 没有加弹窗显示状态的判断,前一个弹窗还在展示/动画过程中时,再次触发
showAlert会重复向当前页面添加背景层和弹窗层,导致多层视图叠加
修复方案
直接修改你的CustomAlert类即可,修改点如下:
- 新增显示状态标记位,避免同时弹出多个弹窗
- 每次展示新弹窗前,先清理
alertView的旧子视图 - 动画结束后同步更新状态标记
修改后的完整CustomAlert代码如下:
class CustomAlert{ struct Constants { static let backgroundAlphaTo: CGFloat = 0.6 } // 标记当前是否有弹窗正在展示 private var isShowing = false private let backgroundView: UIView = { let backgroundView = UIView() backgroundView.backgroundColor = .black backgroundView.alpha = 0 return backgroundView }() private let alertView: UIView = { let alertView = UIView() alertView.backgroundColor = UIColor(rgb: 0x363636, alphaVal: 1) alertView.layer.masksToBounds = true alertView.layer.cornerRadius = 12 return alertView }() private var myTargetView: UIView? func showAlert(with title: String, message: String, on ViewController: UIViewController){ // 如果已有弹窗正在展示,直接返回不重复弹出;如果需要替换旧弹窗可以改为 if isShowing { dismissAlert() } guard !isShowing else { return } guard let targetView = ViewController.view else{ return } // 清理弹窗上的旧子视图,避免内容重叠 alertView.subviews.forEach { $0.removeFromSuperview() } isShowing = true myTargetView = targetView backgroundView.frame = targetView.bounds targetView.addSubview(backgroundView) targetView.addSubview(alertView) alertView.frame = CGRect(x: 40, y: -300, width: targetView.frame.size.width-80, height: 180) let titleLabel = UILabel(frame: CGRect(x: 20, y: 10, width: alertView.frame.size.width, height: 40)) titleLabel.text = title titleLabel.textAlignment = .left titleLabel.font = UIFont(name: "Roboto-Regular", size: 20) titleLabel.textColor = .white alertView.addSubview(titleLabel) let messageLabel = UILabel(frame: CGRect(x: 20, y: 40, width: alertView.frame.size.width-30, height: 60)) messageLabel.text = message messageLabel.font = UIFont(name: "Roboto-Thin", size: 18) messageLabel.textColor = .white messageLabel.numberOfLines = 0 messageLabel.textAlignment = .left alertView.addSubview(messageLabel) let button = UIButton (frame: CGRect(x: alertView.frame.size.width-130, y: alertView.frame.size.height-70, width: (alertView.frame.midX)/2, height: 50)) button.setTitle("Okay", for: .normal) button.applyGradient(colors: [Helper.UIColorFromRGB(0x694BCE).cgColor,Helper.UIColorFromRGB(0x7D3297).cgColor]) button.addTarget(self, action: #selector(dismissAlert), for: .touchUpInside) alertView.addSubview(button) UIView.animate(withDuration: 0.25, animations: { self.backgroundView.alpha = Constants.backgroundAlphaTo}, completion: {done in if done{ UIView.animate(withDuration: 0.25, animations: { self.alertView.center = targetView.center }) } }) } @objc func dismissAlert(){ guard let targetView = myTargetView else{ return } UIView.animate(withDuration: 0.25, animations: { self.alertView.frame = CGRect(x: 40, y: targetView.frame.size.height, width: targetView.frame.size.width-80, height: 180) }, completion: { [weak self] done in guard let self = self else { return } if done{ UIView.animate(withDuration: 0.25, animations: { self.backgroundView.alpha = 0 }, completion: { done in if done { self.alertView.removeFromSuperview() self.backgroundView.removeFromSuperview() // 弹窗完全消失后更新状态 self.isShowing = false } }) } }) } }
内容的提问来源于stack exchange,提问作者Eustache
相关产品推荐
相关产品推荐

