Swift 3.0中如何以编程方式动态设置UIAlertController的自定义对齐位置?
如何动态设置UIAlertController的自定义对齐位置?
这个需求很常见!UIAlertController本身并没有暴露直接修改位置的官方API,但我们可以通过两种实用的方式来实现自定义它的显示位置,下面给你详细拆解:
方案一:直接修改底层视图位置(快速实现)
UIAlertController在present完成后,我们可以通过它的view属性获取到底层弹窗视图,然后直接修改它的center或frame来调整位置。注意一定要在present的completion闭包里操作,确保弹窗视图已经完成初始化和布局。
示例代码如下:
let alert = UIAlertController(title: "title", message: "message", preferredStyle: UIAlertControllerStyle.alert) alert.setValue(self.setFontStyle(text: title, textSize: 16, textStyle: "HelveticaNeue-Medium"), forKey: "attributedTitle") alert.setValue(self.setFontStyle(text: message, textSize: 12, textStyle: "HelveticaNeue"), forKey: "attributedMessage") let cancelAction = UIAlertAction(title: "Dismiss", style: .default) { (result : UIAlertAction) -> Void in alert.dismiss(animated: true, completion: nil) } alert.addAction(cancelAction) // 在present完成后调整位置 self.present(alert, animated: true) { guard let alertView = alert.view else { return } // 示例:将弹窗对齐到某个特定视图的下方 let targetView = self.yourTargetButton // 替换成你的目标视图 let targetFrame = targetView.convert(targetView.bounds, to: self.view) // 计算弹窗的目标中心点(避免超出屏幕) let screenBounds = UIScreen.main.bounds let safeX = max(alertView.bounds.width/2, min(targetFrame.midX, screenBounds.width - alertView.bounds.width/2)) let safeY = max(alertView.bounds.height/2, min(targetFrame.maxY + alertView.bounds.height/2, screenBounds.height - alertView.bounds.height/2)) alertView.center = CGPoint(x: safeX, y: safeY) }
这种方式优点是代码少、快速见效,缺点是依赖UIAlertController的私有视图层级,虽然当前iOS版本稳定可用,但苹果未来可能修改内部实现,所以上线前要多做版本兼容性测试。
方案二:自定义转场动画(灵活可控)
如果需要更稳定的实现,或者想给弹窗添加自定义显示动画,推荐使用自定义转场代理UIViewControllerTransitioningDelegate。这种方式更符合苹果的视图控制器转场规范,兼容性更好。
步骤1:创建自定义转场动画类
class CustomAlertTransition: NSObject, UIViewControllerAnimatedTransitioning { private let targetCenter: CGPoint // 初始化时传入目标位置 init(targetCenter: CGPoint) { self.targetCenter = targetCenter super.init() } // 转场动画时长 func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.3 } // 实现动画逻辑 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let alertVC = transitionContext.viewController(forKey: .to) as? UIAlertController, let alertView = alertVC.view else { transitionContext.completeTransition(false) return } let containerView = transitionContext.containerView containerView.addSubview(alertView) // 初始状态:透明+向上偏移 alertView.alpha = 0 alertView.center = CGPoint(x: targetCenter.x, y: targetCenter.y - 50) // 执行动画到目标位置 UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5, animations: { alertView.alpha = 1 alertView.center = self.targetCenter }) { _ in transitionContext.completeTransition(true) } } }
步骤2:配置并present弹窗
让当前视图控制器遵守UIViewControllerTransitioningDelegate协议,然后设置弹窗的转场代理:
extension YourViewController: UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { // 返回自定义转场实例(这里可以根据需要传递不同的targetCenter) return CustomAlertTransition(targetCenter: CGPoint(x: view.center.x, y: 200)) } } // 创建并配置弹窗 let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert) alert.setValue(self.setFontStyle(text: title, textSize: 16, textStyle: "HelveticaNeue-Medium"), forKey: "attributedTitle") alert.setValue(self.setFontStyle(text: message, textSize: 12, textStyle: "HelveticaNeue"), forKey: "attributedMessage") let cancelAction = UIAlertAction(title: "Dismiss", style: .default) { _ in alert.dismiss(animated: true) } alert.addAction(cancelAction) // 设置转场相关属性 alert.transitioningDelegate = self alert.modalPresentationStyle = .custom self.present(alert, animated: true)
这种方式的优点是稳定性高,完全基于官方API,还能自定义动画效果;缺点是需要写更多代码,适合对弹窗体验有更高要求的场景。
内容的提问来源于stack exchange,提问作者dang
相关产品推荐
相关产品推荐

