Ios 带有swift的自定义警报(UIAlertView)

Ios 带有swift的自定义警报(UIAlertView),ios,swift,uialertview,Ios,Swift,Uialertview,如何使用Swift创建自定义警报?我试着从Objective c翻译一个指南,但加载了一个全屏布局 为了方便起见,我可以加载一个带有透明背景的新布局,我尝试了以下方法: listaalertviewcontroller.view.backgroundColor = UIColor.clearColor() let purple = UIColor.purpleColor() // 1.0 alpha let semi = purple.colorWithAlphaComp

如何使用Swift创建自定义警报?我试着从Objective c翻译一个指南,但加载了一个全屏布局

为了方便起见,我可以加载一个带有透明背景的新布局,我尝试了以下方法:

    listaalertviewcontroller.view.backgroundColor = UIColor.clearColor()
    let purple = UIColor.purpleColor() // 1.0 alpha
    let semi = purple.colorWithAlphaComponent(0.5)

    listaalertviewcontroller.view.backgroundColor = semi


    presentingViewController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext

    self.presentViewController(listaalertviewcontroller, animated: true, completion: nil)
在动画中它是透明的,但当动画结束时它是不透明的。。。我关闭了视图中的不透明选项。。。我做错了什么?

在Swift 5和Xcode 10中测试的代码

如何制作您自己的自定义警报 我想做类似的事情。首先,
UIAlertView
被弃用,取而代之的是
UIAlertController
。有关显示警报的标准方式,请参见此答案:

而且
UIAlertView
UIAlertController
都不允许进行大量定制。一种选择是使用一些第三方代码。然而,我发现通过显示另一个视图控制器来创建自己的警报并不是那么困难

这里的例子只是一个概念证明。您可以按照任何方式设计警报

故事板 您应该有两个视图控制器。您的第二个视图控制器将成为您的警报。将类名设置为
AlertViewContoller
,将情节提要ID设置为
alert
。(这两个名称都是我们在下面的代码中定义的,没有什么特别之处。如果需要,可以先添加代码。如果先添加代码,可能会更容易。)

将根视图(在警报视图控制器中)的背景色设置为“清除”(或半透明黑色适合警报)。添加另一个
ui视图
,并使用约束将其居中。用它作为你的警报背景,把你想要的东西放进去。例如,我添加了一个
ui按钮

代码 ViewController.swift

import UIKit
class ViewController: UIViewController {

    @IBAction func showAlertButtonTapped(_ sender: UIButton) {
        
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let myAlert = storyboard.instantiateViewController(withIdentifier: "alert")
        myAlert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        myAlert.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
        self.present(myAlert, animated: true, completion: nil)
    }
}
import UIKit
class AlertViewController: UIViewController {
    
    @IBAction func dismissButtonTapped(_ sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }
}
import UIKit
class AlertViewController: UIViewController {

    @IBAction func dismissButtonTapped(sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }
}
AlertViewController.swift

import UIKit
class ViewController: UIViewController {

    @IBAction func showAlertButtonTapped(_ sender: UIButton) {
        
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let myAlert = storyboard.instantiateViewController(withIdentifier: "alert")
        myAlert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        myAlert.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
        self.present(myAlert, animated: true, completion: nil)
    }
}
import UIKit
class AlertViewController: UIViewController {
    
    @IBAction func dismissButtonTapped(_ sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }
}
import UIKit
class AlertViewController: UIViewController {

    @IBAction func dismissButtonTapped(sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }
}
别忘了挂上插座

您可以将
onTouchUp
事件侦听器添加到后台视图中,以便在用户单击弹出窗口外部时关闭弹出窗口

就这样。你应该能够发出任何你现在能想象到的警报。不需要第三方代码

这是我制作的另一个自定义警报。仍然很难看,但它显示出你可以做更多的事情

其他选择
不过,有时没有必要重新发明轮子。我对第三方项目(MIT许可证)印象深刻。它是用Swift编写的,但您也可以将其用于Objective-C项目。它提供了广泛的可定制性。

以下是Swift 3代码。非常感谢@Suragch提供了创建自定义AlertView的绝妙方法

ViewController.swift

import UIKit
class ViewController: UIViewController {

@IBAction func showAlertButtonTapped(sender: UIButton) {

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let myAlert = storyboard.instantiateViewController(withIdentifier: "storyboardID")
        myAlert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        myAlert.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
        self.present(myAlert, animated: true, completion: nil)

}
AlertViewController.swift

import UIKit
class ViewController: UIViewController {

    @IBAction func showAlertButtonTapped(_ sender: UIButton) {
        
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let myAlert = storyboard.instantiateViewController(withIdentifier: "alert")
        myAlert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        myAlert.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
        self.present(myAlert, animated: true, completion: nil)
    }
}
import UIKit
class AlertViewController: UIViewController {
    
    @IBAction func dismissButtonTapped(_ sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }
}
import UIKit
class AlertViewController: UIViewController {

    @IBAction func dismissButtonTapped(sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }
}
要使其更有趣或在iOS中产生默认效果,可以添加VisualEffectView或将主UIView的颜色更改为深色,并将其alpha设置为70%。我更喜欢第二种方法,因为模糊效果不如70 alpha视图的效果平滑

具有VisualEffectView的效果:

使用70 Alpha的UIView的效果:

使用

实现这一点很容易。按照以下步骤操作:

  • 向下拖动项目目录中的AlertView文件夹

  • 显示警报视图弹出窗口


  • 如今,警报仅仅是一个简单的视图控制器。您可以编写一个显示的视图控制器,其行为类似于警报-即,它会弹出到屏幕上并使其后面的任何内容变暗-但它是您的视图控制器,您可以随意为其提供任何您喜欢的界面

    为了让您开始,我编写了一个可供下载和运行,并可根据您的实际需要进行修改的应用程序

    我将显示代码的关键部分。“警报”视图控制器在其初始值设定项中,将其自己的模式表示样式设置为“自定义”,并设置转换委托:

    class CustomAlertViewController : UIViewController {
        let transitioner = CAVTransitioner()
    
        override init(nibName: String?, bundle: Bundle?) {
            super.init(nibName: nibName, bundle: bundle)
            self.modalPresentationStyle = .custom
            self.transitioningDelegate = self.transitioner
        }
    
        convenience init() {
            self.init(nibName:nil, bundle:nil)
        }
    
        required init?(coder: NSCoder) {
            fatalError("NSCoding not supported")
        }
    }
    
    class CAVTransitioner : NSObject, UIViewControllerTransitioningDelegate {
        func presentationController(
            forPresented presented: UIViewController,
            presenting: UIViewController?,
            source: UIViewController)
            -> UIPresentationController? {
                return MyPresentationController(
                    presentedViewController: presented, presenting: presenting)
        }
    }
    
    class MyPresentationController : UIPresentationController {
    
        func decorateView(_ v:UIView) {
            // iOS 8 doesn't have this
    //        v.layer.borderColor = UIColor.blue.cgColor
    //        v.layer.borderWidth = 2
            v.layer.cornerRadius = 8
    
            let m1 = UIInterpolatingMotionEffect(
                keyPath:"center.x", type:.tiltAlongHorizontalAxis)
            m1.maximumRelativeValue = 10.0
            m1.minimumRelativeValue = -10.0
            let m2 = UIInterpolatingMotionEffect(
                keyPath:"center.y", type:.tiltAlongVerticalAxis)
            m2.maximumRelativeValue = 10.0
            m2.minimumRelativeValue = -10.0
            let g = UIMotionEffectGroup()
            g.motionEffects = [m1,m2]
            v.addMotionEffect(g)
        }
    
        override func presentationTransitionWillBegin() {
            self.decorateView(self.presentedView!)
            let vc = self.presentingViewController
            let v = vc.view!
            let con = self.containerView!
            let shadow = UIView(frame:con.bounds)
            shadow.backgroundColor = UIColor(white:0, alpha:0.4)
            shadow.alpha = 0
            con.insertSubview(shadow, at: 0)
            shadow.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            let tc = vc.transitionCoordinator!
            tc.animate(alongsideTransition: { _ in
                shadow.alpha = 1
            }) { _ in
                v.tintAdjustmentMode = .dimmed
            }
        }
    
        override func dismissalTransitionWillBegin() {
            let vc = self.presentingViewController
            let v = vc.view!
            let con = self.containerView!
            let shadow = con.subviews[0]
            let tc = vc.transitionCoordinator!
            tc.animate(alongsideTransition: { _ in
                shadow.alpha = 0
            }) { _ in
                v.tintAdjustmentMode = .automatic
            }
        }
    
        override var frameOfPresentedViewInContainerView : CGRect {
            // we want to center the presented view at its "native" size
            // I can think of a lot of ways to do this,
            // but here we just assume that it *is* its native size
            let v = self.presentedView!
            let con = self.containerView!
            v.center = CGPoint(x: con.bounds.midX, y: con.bounds.midY)
            return v.frame.integral
        }
    
        override func containerViewWillLayoutSubviews() {
            // deal with future rotation
            // again, I can think of more than one approach
            let v = self.presentedView!
            v.autoresizingMask = [
                .flexibleTopMargin, .flexibleBottomMargin,
                .flexibleLeftMargin, .flexibleRightMargin
            ]
            v.translatesAutoresizingMaskIntoConstraints = true
        }
    
    }
    
    extension CAVTransitioner { // UIViewControllerTransitioningDelegate
        func animationController(
            forPresented presented:UIViewController,
            presenting: UIViewController,
            source: UIViewController)
            -> UIViewControllerAnimatedTransitioning? {
                return self
        }
    
        func animationController(
            forDismissed dismissed: UIViewController)
            -> UIViewControllerAnimatedTransitioning? {
                return self
        }
    }
    
    extension CAVTransitioner : UIViewControllerAnimatedTransitioning {
        func transitionDuration(
            using transitionContext: UIViewControllerContextTransitioning?)
            -> TimeInterval {
                return 0.25
        }
    
        func animateTransition(
            using transitionContext: UIViewControllerContextTransitioning) {
    
            let con = transitionContext.containerView
    
            let v1 = transitionContext.view(forKey: .from)
            let v2 = transitionContext.view(forKey: .to)
    
            // we are using the same object (self) as animation controller
            // for both presentation and dismissal
            // so we have to distinguish the two cases
    
            if let v2 = v2 { // presenting
                con.addSubview(v2)
                let scale = CGAffineTransform(scaleX: 1.6, y: 1.6)
                v2.transform = scale
                v2.alpha = 0
                UIView.animate(withDuration: 0.25, animations: {
                    v2.alpha = 1
                    v2.transform = .identity
                }) { _ in
                    transitionContext.completeTransition(true)
                }
            } else if let v1 = v1 { // dismissing
                UIView.animate(withDuration: 0.25, animations: {
                    v1.alpha = 0
                }) { _ in
                    transitionContext.completeTransition(true)
                }
            }
    
        }
    }
    
    所有工作均由过渡代表完成:

    class CustomAlertViewController : UIViewController {
        let transitioner = CAVTransitioner()
    
        override init(nibName: String?, bundle: Bundle?) {
            super.init(nibName: nibName, bundle: bundle)
            self.modalPresentationStyle = .custom
            self.transitioningDelegate = self.transitioner
        }
    
        convenience init() {
            self.init(nibName:nil, bundle:nil)
        }
    
        required init?(coder: NSCoder) {
            fatalError("NSCoding not supported")
        }
    }
    
    class CAVTransitioner : NSObject, UIViewControllerTransitioningDelegate {
        func presentationController(
            forPresented presented: UIViewController,
            presenting: UIViewController?,
            source: UIViewController)
            -> UIPresentationController? {
                return MyPresentationController(
                    presentedViewController: presented, presenting: presenting)
        }
    }
    
    class MyPresentationController : UIPresentationController {
    
        func decorateView(_ v:UIView) {
            // iOS 8 doesn't have this
    //        v.layer.borderColor = UIColor.blue.cgColor
    //        v.layer.borderWidth = 2
            v.layer.cornerRadius = 8
    
            let m1 = UIInterpolatingMotionEffect(
                keyPath:"center.x", type:.tiltAlongHorizontalAxis)
            m1.maximumRelativeValue = 10.0
            m1.minimumRelativeValue = -10.0
            let m2 = UIInterpolatingMotionEffect(
                keyPath:"center.y", type:.tiltAlongVerticalAxis)
            m2.maximumRelativeValue = 10.0
            m2.minimumRelativeValue = -10.0
            let g = UIMotionEffectGroup()
            g.motionEffects = [m1,m2]
            v.addMotionEffect(g)
        }
    
        override func presentationTransitionWillBegin() {
            self.decorateView(self.presentedView!)
            let vc = self.presentingViewController
            let v = vc.view!
            let con = self.containerView!
            let shadow = UIView(frame:con.bounds)
            shadow.backgroundColor = UIColor(white:0, alpha:0.4)
            shadow.alpha = 0
            con.insertSubview(shadow, at: 0)
            shadow.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            let tc = vc.transitionCoordinator!
            tc.animate(alongsideTransition: { _ in
                shadow.alpha = 1
            }) { _ in
                v.tintAdjustmentMode = .dimmed
            }
        }
    
        override func dismissalTransitionWillBegin() {
            let vc = self.presentingViewController
            let v = vc.view!
            let con = self.containerView!
            let shadow = con.subviews[0]
            let tc = vc.transitionCoordinator!
            tc.animate(alongsideTransition: { _ in
                shadow.alpha = 0
            }) { _ in
                v.tintAdjustmentMode = .automatic
            }
        }
    
        override var frameOfPresentedViewInContainerView : CGRect {
            // we want to center the presented view at its "native" size
            // I can think of a lot of ways to do this,
            // but here we just assume that it *is* its native size
            let v = self.presentedView!
            let con = self.containerView!
            v.center = CGPoint(x: con.bounds.midX, y: con.bounds.midY)
            return v.frame.integral
        }
    
        override func containerViewWillLayoutSubviews() {
            // deal with future rotation
            // again, I can think of more than one approach
            let v = self.presentedView!
            v.autoresizingMask = [
                .flexibleTopMargin, .flexibleBottomMargin,
                .flexibleLeftMargin, .flexibleRightMargin
            ]
            v.translatesAutoresizingMaskIntoConstraints = true
        }
    
    }
    
    extension CAVTransitioner { // UIViewControllerTransitioningDelegate
        func animationController(
            forPresented presented:UIViewController,
            presenting: UIViewController,
            source: UIViewController)
            -> UIViewControllerAnimatedTransitioning? {
                return self
        }
    
        func animationController(
            forDismissed dismissed: UIViewController)
            -> UIViewControllerAnimatedTransitioning? {
                return self
        }
    }
    
    extension CAVTransitioner : UIViewControllerAnimatedTransitioning {
        func transitionDuration(
            using transitionContext: UIViewControllerContextTransitioning?)
            -> TimeInterval {
                return 0.25
        }
    
        func animateTransition(
            using transitionContext: UIViewControllerContextTransitioning) {
    
            let con = transitionContext.containerView
    
            let v1 = transitionContext.view(forKey: .from)
            let v2 = transitionContext.view(forKey: .to)
    
            // we are using the same object (self) as animation controller
            // for both presentation and dismissal
            // so we have to distinguish the two cases
    
            if let v2 = v2 { // presenting
                con.addSubview(v2)
                let scale = CGAffineTransform(scaleX: 1.6, y: 1.6)
                v2.transform = scale
                v2.alpha = 0
                UIView.animate(withDuration: 0.25, animations: {
                    v2.alpha = 1
                    v2.transform = .identity
                }) { _ in
                    transitionContext.completeTransition(true)
                }
            } else if let v1 = v1 { // dismissing
                UIView.animate(withDuration: 0.25, animations: {
                    v1.alpha = 0
                }) { _ in
                    transitionContext.completeTransition(true)
                }
            }
    
        }
    }
    
    它看起来像很多代码,我想是的,但它几乎只限于一个类,完全是样板;复制粘贴即可。您所要做的就是编写“警报”视图控制器的内部接口和行为,为其提供按钮和文本以及您想要的任何其他内容,就像您为任何其他视图控制器所做的一样。

    swift 4中的自定义警报UIView类。用法## 强文本
    ##使用Tabbar自定义警报

        let custView = Bundle.main.loadNibNamed("Dialouge", owner: self, options: 
         nil)![0] as? Dialouge
            custView?.lblDescription.text = "Are you sure you want to delete post?"
            custView?.lblTitle.text = "Delete Post"
            custView?.btnLeft.setTitle("Yes", for: .normal)
            custView?.btnRight.setTitle("No", for: .normal)
            custView?.leftAction = {
                self.deletePost(postId: self.curr_post.id,completion: {
                    custView?.removeFromSuperview()
                })
            }
            custView?.rightAction = {
                custView?.removeFromSuperview()
            }
            if let tbc = self.parentt?.tabBarController {
                custView?.frame = tbc.view.frame
                DispatchQueue.main.async {
                    tbc.view.addSubview(custView!)
                }
            }else if let tbc = self.parView?.parenttprof {
                custView?.frame = tbc.view.frame
                DispatchQueue.main.async {
                    tbc.view.addSubview(custView!)
                }
            }
            else
            {
                custView?.frame = self.parView?.view.frame ?? CGRect.zero
                DispatchQueue.main.async {
                    self.parView?.view.addSubview(custView!)
                }
                }
    

    由于iOS 7,您无法自定义。如中所述:UIAlertView类旨在按原样使用,不支持子类化。此类的视图层次结构是私有的,不能修改。我编辑我的问题!谢谢这将导致Interface Builder文件中的未知类AlertViewController异常。@如果要设置按钮的动态标题,请在何处编写代码?@Jasmit,为按钮添加一个
    @IBOutlet
    ,然后在加载
    AlertViewController
    时将按钮文本更改为您想要的任何内容。谢谢您的回答。当触摸到对话框外部时,如何关闭对话框?如果任何人在执行此操作时遇到问题并出现SIGBRT错误,则其原因是您还需要勾选“从目标继承模块”复选框。
    let blurFx=UIBlurEffectStyle(style:UIBlurEffectStyle.dark)let blurFxView=UIVisualEffectView(effect:blurFx)blurFxView.frame=view.bounds blurFxView.autoresizingMask=[.flexibleWidth,.flexibleHeight]视图。插入子视图(blurFxView,位于:0)
    我查看了您的GitHub链接,项目已断开。它引用的是不存在的字体和颜色。如果您修复了项目并使其正常工作,我将更新您的答案。@PeterSuwara我已经更新了git存储库。你们宝贵的反馈让我们有动力做越来越多的开源项目。谢谢你的好帖。我运行了代码,注释掉了UIInterpolingMotionEffect。我看不见一只猫