class MyAlertView: UIView { let titleLabel: UILabel = { let v = UILabel() v.translatesAutoresizingMaskIntoConstraints = false v.textAlignment = .center v.text = "My Alert View" v.font = UIFont.systemFont(ofSize: 20.0, weight: .bold) v.textColor = .red return v }() let messageLabel: UILabel = { let v = UILabel() v.translatesAutoresizingMaskIntoConstraints = false v.textAlignment = .center v.numberOfLines = 0 v.font = UIFont.systemFont(ofSize: 15.0, weight: .regular) v.textColor = .blue return v }() override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } func commonInit() -> Void { backgroundColor = UIColor.black.withAlphaComponent(0.25) layer.cornerRadius = 16 layer.borderColor = UIColor.black.cgColor layer.borderWidth = 2 addSubview(titleLabel) addSubview(messageLabel) NSLayoutConstraint.activate([ // constrain title label to width of self, 16-pts from the top titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 16.0), titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor), titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor), // constrain Top of message label to Bottom of title label + 10-pts "spacing" messageLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10.0), // 16-pts leading and trailing messageLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16.0), messageLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16.0), // bottom to self bottom + 16-pts "spacing" messageLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16.0), ]) } } class ShowMyAlertViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 2 seconds after view appears, show the alert DispatchQueue.main.asyncAfter(deadline: .now() + 2) { self.showMyAlert("This is a test of showing a custom \"Alert / Notification\" view, which will dismiss itself after 5 seconds.") } } func showMyAlert(_ msg: String) -> Void { // instantiate MyAlertView let v = MyAlertView() // set the label's text v.messageLabel.text = msg v.translatesAutoresizingMaskIntoConstraints = false // add it to self's view view.addSubview(v) // hidden constraint will place the BOTTOM of the view 10-pts above the top of self's view let hiddenConstraint = v.bottomAnchor.constraint(equalTo: view.topAnchor, constant: -10.0) // visible constraint will place the TOP of the view 10-pts below the top of self's view (respecting safe area) let visibleConstraint = v.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10.0) NSLayoutConstraint.activate([ // center the alert view horizontally v.centerXAnchor.constraint(equalTo: view.centerXAnchor), // make its width 80% of the view v.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8), // height will be determined by the content of the view // start with view above self's view frame ("hidden") hiddenConstraint, ]) // allow the alert view to start at its hidden position DispatchQueue.main.async { // swap active constraints hiddenConstraint.isActive = false visibleConstraint.isActive = true // animate it into view UIView.animate(withDuration: 0.3, animations: { self.view.layoutIfNeeded() }, completion: { done in // wait 5 seconds DispatchQueue.main.asyncAfter(deadline: .now() + 5) { // swap active constraints visibleConstraint.isActive = false hiddenConstraint.isActive = true // animate it out of view UIView.animate(withDuration: 0.3, animations: { self.view.layoutIfNeeded() }, completion: { done in // remove it v.removeFromSuperview() }) } }) } } }