Swift自定义弹窗视图无法显示边框及背景模糊等效果的问题
解决自定义弹窗的三个核心问题
我帮你拆解一下当前遇到的三个问题,逐个给出修复方案:
一、弹窗样式(边框、阴影)不显示的问题
你现在把layer的圆角、边框、阴影属性都加在了CustomAlertView本身上,但实际上你的CustomAlertView是作为容器,真正的弹窗内容是它内部的customAlertView子视图。而且你的clipsToBounds和masksToBounds设置有点冲突——阴影需要外层容器masksToBounds = false,但圆角效果应该应用在内部的弹窗内容视图上。
修复步骤:
- 把边框、圆角属性应用到内部的
customAlertView子视图 - 阴影属性保留在外层的
CustomAlertView容器上,避免被裁切
修改后的样式代码:
func someAction() { // 先给外层容器设置全屏frame,确保覆盖整个屏幕 customAlert.frame = self.view.bounds self.view.addSubview(customAlert) // 操作内部的弹窗内容视图 let alertContent = customAlert.customAlertView alertContent.layer.cornerRadius = 8 alertContent.layer.borderWidth = 10 alertContent.layer.borderColor = UIColor.gray.cgColor alertContent.clipsToBounds = true // 确保圆角生效 // 给外层容器加阴影(阴影要在弹窗外面,所以外层不能裁切) customAlert.layer.masksToBounds = false customAlert.layer.shadowOffset = CGSize(width:-15, height:20) customAlert.layer.shadowRadius = 5 customAlert.layer.shadowOpacity = 0.5 // 阴影路径匹配内部弹窗的实际frame let shadowPath = UIBezierPath(roundedRect: alertContent.frame, cornerRadius: alertContent.layer.cornerRadius) customAlert.layer.shadowPath = shadowPath.cgPath // ... 按钮回调设置 ... }
二、主视图TableView仍可滚动的问题
这是因为弹窗没有拦截底层视图的交互,需要添加半透明遮罩来阻断底层操作,同时把弹窗放在遮罩上方:
- 在
CustomAlertView的commonInit()里添加背景遮罩:
private func commonInit() { Bundle.main.loadNibNamed("CustomAlertView", owner: self) guard let content = customAlertView else { return } // 添加全屏半透明遮罩 let backgroundMask = UIView(frame: self.bounds) backgroundMask.backgroundColor = UIColor.black.withAlphaComponent(0.5) backgroundMask.autoresizingMask = [.flexibleHeight, .flexibleWidth] self.addSubview(backgroundMask) // 把弹窗内容放在遮罩上面 self.addSubview(content) content.frame = self.bounds content.autoresizingMask = [.flexibleHeight, .flexibleWidth] // 可选:给遮罩加点击关闭弹窗的逻辑 backgroundMask.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissAlert))) } @objc private func dismissAlert() { self.removeFromSuperview() }
- 或者在弹窗显示时临时禁用底层视图交互:
func someAction() { self.view.isUserInteractionEnabled = false // 禁用底层操作 // ... 弹窗添加和样式设置 ... } // 在按钮点击方法里恢复交互 @objc func button1tapped() { self.view.isUserInteractionEnabled = true customAlert.removeFromSuperview() }
三、自定义视图上的按钮无响应的问题
大概率是按钮的交互逻辑没绑定对,或者视图层级导致按钮不在可点击区域。推荐把按钮回调封装在CustomAlertView内部,用闭包回调给ViewController,这样更清晰也不容易出错:
修改CustomAlertView添加闭包回调:
class CustomAlertView : UIView { @IBOutlet weak var customAlertView : UIView! @IBOutlet weak var button1 : UIButton! @IBOutlet weak var button2 : UIButton! // 定义回调闭包 var onButton1Tapped: (() -> Void)? var onButton2Tapped: (() -> Void)? override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() } private func commonInit() { Bundle.main.loadNibNamed("CustomAlertView", owner: self) guard let content = customAlertView else { return } // 添加背景遮罩(参考上面的代码) let backgroundMask = UIView(frame: self.bounds) backgroundMask.backgroundColor = UIColor.black.withAlphaComponent(0.5) backgroundMask.autoresizingMask = [.flexibleHeight, .flexibleWidth] self.addSubview(backgroundMask) self.addSubview(content) content.frame = self.bounds content.autoresizingMask = [.flexibleHeight, .flexibleWidth] // 内部绑定按钮点击事件 button1.addTarget(self, action: #selector(button1Action), for: .touchUpInside) button2.addTarget(self, action: #selector(button2Action), for: .touchUpInside) } @objc private func button1Action() { onButton1Tapped?() // 触发回调 self.removeFromSuperview() } @objc private func button2Action() { onButton2Tapped?() // 触发回调 self.removeFromSuperview() } }
然后在ViewController里使用闭包:
func someAction() { let customAlert = CustomAlertView(frame: self.view.bounds) // 设置按钮回调逻辑 customAlert.onButton1Tapped = { [weak self] in self?.view.isUserInteractionEnabled = true // 这里写button1点击后的业务逻辑 } customAlert.onButton2Tapped = { [weak self] in self?.view.isUserInteractionEnabled = true // 这里写button2点击后的业务逻辑 } self.view.isUserInteractionEnabled = false self.view.addSubview(customAlert) // ... 弹窗样式设置 ... }
按照上面的方案调整后,三个问题应该都能解决,你可以根据自己的需求微调遮罩透明度、弹窗位置等细节。
内容的提问来源于stack exchange,提问作者Anilkumar iOS Developer
相关产品推荐
相关产品推荐

