使用swift自定义警报(UIAlertView)

bogh5gae  于 2023-03-11  发布在  Swift
关注(0)|答案(5)|浏览(136)

我如何使用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)

在动画中它是透明的,但当动画结束时它是不透明的...我在视图中关闭了不透明选项...我做错了什么?

xmq68pz9

xmq68pz91#

  • 代码在Swift 5和Xcode 10中测试 *

如何制作自己的自定义提醒

我想做一些类似的事情。首先,UIAlertView被弃用,而UIAlertController被支持。请参阅以下答案以了解显示警报的标准方式:

  • 如何在Swift中创建UIAlertView?

而且UIAlertViewUIAlertController都不允许进行太多的自定义。一种选择是使用一些第三方代码。然而,我发现通过显示另一个视图控制器模式来创建自己的警报并不困难。
这里的例子只是一个概念验证。你可以用任何你想要的方式来设计你的提醒。

故事板

你应该有两个视图控制器。你的第二个视图控制器将是你的警报。设置类名为AlertViewContoller,故事板ID为alert。(这两个名称都是我们在下面的代码中自己定义的,没有什么特别的。如果你愿意,你可以先添加代码。如果你先添加代码,实际上可能会更容易。)

将根视图的背景颜色(在警报视图控制器中)设置为透明(或半透明黑色更适合警报)。添加另一个UIView,并将其居中放置,同时进行约束。将其用作警报背景,并在其中放置您想要的内容。对于我的示例,我添加了一个UIButton

代码

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)
    }
}

AlertViewController.swift

import UIKit
class AlertViewController: UIViewController {
    
    @IBAction func dismissButtonTapped(_ sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }
}

别忘了接通电源插座。
您可以在背景视图中添加一个onTouchUp事件侦听器,以便在用户单击弹出窗口外部时关闭弹出窗口。
就是这样。你现在应该可以发出任何你能想象到的警报。不需要第三方代码。
这是我制作的另一个自定义提醒。仍然很丑,但它显示了更多你可以做的事情。

其他选项

不过,有时候不需要重新发明轮子。第三方项目SDCAlertView(MIT许可证)给我留下了深刻的印象。它是用Swift编写的,但你也可以在Objective-C项目中使用它。它提供了广泛的可定制性。

qzwqbdag

qzwqbdag2#

以下是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 AlertViewController: UIViewController {

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

为了让它更有趣或者在iOS中使用默认效果,你可以添加一个VisualEffectView,或者将主UIView的颜色改为深色,并将其alpha设置为70%。我更喜欢第二种方法,因为模糊效果不如alpha为70的视图平滑。

可视化效果视图的效果:

使用70 Alpha的UIView的效果:

vof42yt1

vof42yt13#

现在,警报仅仅是一个简单的呈现视图控制器,你可以编写一个呈现视图控制器,它的行为类似于警报--也就是说,它会弹出屏幕,并使屏幕后面的内容变暗--但它是你的视图控制器,你可以自由地给予它任何你喜欢的界面。
为了让您开始,我编写了一个github project,您可以下载并运行它,并根据实际需要进行修改。
我将展示代码的关键部分,“alert”视图控制器在其初始化器中将自己的模态表示样式设置为custom,并设置一个转换委托:

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)
            }
        }

    }
}

它看起来像很多代码,我想也是,但它几乎完全局限于一个类,这完全是样板文件;你所要做的就是编写你的“警报”视图控制器的内部接口和行为,给它按钮和文本以及你想要的任何东西,就像你对任何其他视图控制器所做的那样。

gmol1639

gmol16394#

swift 4中的自定义警报UIView类和用法##

import UIKit

    class Dialouge: UIView {
    @IBOutlet weak var lblTitle: UILabel!
    @IBOutlet weak var lblDescription: UILabel!
    @IBOutlet weak var btnLeft: UIButton!
    @IBOutlet weak var btnRight: UIButton!
    @IBOutlet weak var viewBg: UIButton!

    var leftAction  = {}
    var rightAction  = {}

    override func draw(_ rect: CGRect)
    {

        self.btnRight.layer.cornerRadius = self.btnRight.frame.height/2
        self.btnLeft.layer.cornerRadius = self.btnLeft.frame.height/2
        self.btnLeft.layer.borderWidth = 1.0
        self.btnLeft.layer.borderColor = #colorLiteral(red: 0.267678082, green: 0.2990377247, blue: 0.7881471515, alpha: 1)
    }
    @IBAction func leftAction(_ sender: Any) {

        leftAction()
    }

    @IBAction func rightAction(_ sender: Any) {
        rightAction()
    }
    @IBAction func bgTapped(_ sender: Any) {
        self.removeFromSuperview()
    }
    }
  • 强文本 *

##使用选项卡栏的自定义警报

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!)
            }
            }
jum4pzuy

jum4pzuy5#

使用https://github.com/shantaramk/Custom-Alert-View
实现这一点毫不费力。请遵循以下步骤:
1.向下拖动项目目录中的AlertView文件夹
1.显示警报视图弹出窗口

func showUpdateProfilePopup(_ message: String) {
    let alertView = AlertView(title: AlertMessage.success, message: message, okButtonText: LocalizedStrings.okay, cancelButtonText: "") { (_, button) in
            if button == .other {
                self.navigationController?.popViewController(animated: true)
        }
    }
    alertView.show(animated: true)
}

相关问题