107

Is there any way to make a toast message in swift ?

I have tried in objective c but could not find solution in swift.

[self.view makeToast:@"Account created Successfully" duration:0.5 position:@"bottom"]; 
2
  • 1
    github.com/Rannie/Toast-Swift Commented Jul 21, 2015 at 13:30
  • To anyone who is searching for this I would first ask do you really need this? I would say that toasts are more common on Android than on iOS. Personally as a long time iOS user I think toasts are more annoying than useful and if an action was completed successfully then you do not need a toast for that. Commented Oct 13, 2022 at 14:15

26 Answers 26

247
extension UIViewController { func showToast(message : String, font: UIFont) { let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 75, y: self.view.frame.size.height-100, width: 150, height: 35)) toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6) toastLabel.textColor = UIColor.white toastLabel.font = font toastLabel.textAlignment = .center; toastLabel.text = message toastLabel.alpha = 1.0 toastLabel.layer.cornerRadius = 10; toastLabel.clipsToBounds = true self.view.addSubview(toastLabel) UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: { toastLabel.alpha = 0.0 }, completion: {(isCompleted) in toastLabel.removeFromSuperview() }) } } 

Use like this:

self.showToast(message: "Your Toast Message", font: .systemFont(ofSize: 12.0)) 
Sign up to request clarification or add additional context in comments.

18 Comments

Perfect answer. You can add 'toastLabel.font = UIFont(name: "IranSansMobile", size: 19)' in order to change font of toast message.
The label should be removed from the view when the animation ends.
@Sulthan you are welcome for an edit or upgrade of the answer, else i will update the answer soon !!
If you want to show the full message with multiline ,you can use something like this : let toastLabel = UILabel(frame: CGRect(x: 0, y: self.view.frame.size.height-100, width: (self.view.frame.width - 10), height: 35)) toastLabel.numberOfLines = 0 you can change the height accordingly.
the answer is almost perfect because it does not work if you have something displayed in fullscreen, you need to change the addsubview by UIApplication.shared.keyWindow?.addSubview(toastLabel)
|
73

For Swift 4

My version of a Toast that uses layout constraints, with the advantage that it works for any text size, as is (based in the response of Tony Franzis):

Just call: Toast.show(message: "My message", myViewControllerName)

class Toast { static func show(message: String, controller: UIViewController) { let toastContainer = UIView(frame: CGRect()) toastContainer.backgroundColor = UIColor.black.withAlphaComponent(0.6) toastContainer.alpha = 0.0 toastContainer.layer.cornerRadius = 25; toastContainer.clipsToBounds = true let toastLabel = UILabel(frame: CGRect()) toastLabel.textColor = UIColor.white toastLabel.textAlignment = .center; toastLabel.font.withSize(12.0) toastLabel.text = message toastLabel.clipsToBounds = true toastLabel.numberOfLines = 0 toastContainer.addSubview(toastLabel) controller.view.addSubview(toastContainer) toastLabel.translatesAutoresizingMaskIntoConstraints = false toastContainer.translatesAutoresizingMaskIntoConstraints = false let a1 = NSLayoutConstraint(item: toastLabel, attribute: .leading, relatedBy: .equal, toItem: toastContainer, attribute: .leading, multiplier: 1, constant: 15) let a2 = NSLayoutConstraint(item: toastLabel, attribute: .trailing, relatedBy: .equal, toItem: toastContainer, attribute: .trailing, multiplier: 1, constant: -15) let a3 = NSLayoutConstraint(item: toastLabel, attribute: .bottom, relatedBy: .equal, toItem: toastContainer, attribute: .bottom, multiplier: 1, constant: -15) let a4 = NSLayoutConstraint(item: toastLabel, attribute: .top, relatedBy: .equal, toItem: toastContainer, attribute: .top, multiplier: 1, constant: 15) toastContainer.addConstraints([a1, a2, a3, a4]) let c1 = NSLayoutConstraint(item: toastContainer, attribute: .leading, relatedBy: .equal, toItem: controller.view, attribute: .leading, multiplier: 1, constant: 65) let c2 = NSLayoutConstraint(item: toastContainer, attribute: .trailing, relatedBy: .equal, toItem: controller.view, attribute: .trailing, multiplier: 1, constant: -65) let c3 = NSLayoutConstraint(item: toastContainer, attribute: .bottom, relatedBy: .equal, toItem: controller.view, attribute: .bottom, multiplier: 1, constant: -75) controller.view.addConstraints([c1, c2, c3]) UIView.animate(withDuration: 0.5, delay: 0.0, options: .curveEaseIn, animations: { toastContainer.alpha = 1.0 }, completion: { _ in UIView.animate(withDuration: 0.5, delay: 1.5, options: .curveEaseOut, animations: { toastContainer.alpha = 0.0 }, completion: {_ in toastContainer.removeFromSuperview() }) }) } } 

5 Comments

@Samo nice, thanks. Just the toastContainer is partly hidden behind the UITabBar when using an iPhone X. In c3 I changed -75 to -100 to fix it.
It's wonderful and allows you to do it without a 3rd party. I reuse it everywhere in my app. Thanks for this answer.
Wonderful! But I've changed a bit constraints for toastContainer to have dynamic width and make it as an extension of UIViewController. Here is: let c1 = NSLayoutConstraint(item: toastContainer, attribute: .width, relatedBy: .lessThanOrEqual, toItem: view, attribute: .width, multiplier: 1, constant: -90) let c2 = NSLayoutConstraint(item: toastContainer, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 1)
to help anyone else out, Put the class into it's own swift file. then in your calling ViewController, call it like so Toast.show(message: "My message", controller: self) I also had to change the c3 constraint to -150
@Samo nice solution... I changed the bottom layout constraint to use the safe area instead...might be helpful to others, toItem: controller.view.safeAreaLayoutGuide then use the constant attribute to space it further away from tab or navigation bar. Thanks!!
18

There is a 3rd party library that supports customizable toast notification with single line of code. Here is a simple example of it:

import Toast_Swift ... // basic usage self.view.makeToast("This is a piece of toast") // toast with a specific duration and position self.view.makeToast("This is a piece of toast", duration: 3.0, position: .top) 

https://github.com/scalessec/Toast-Swift

(Updated for Swift 3/4+)

1 Comment

I tried your answer from github source code . It's working fine.
17

I have two more solutions on Swift 5:

Best solution (in my opinion)

Advantage:

  1. Works correctly when rotating the screen.
  2. Constraints are used for positioning.
  3. Works correctly with SafeArea.

Disadvantages:

  1. It is required to extend the UILabel class to add indents. One could do without this by placing the UILabel in the UIVIew.

Code:

class ToastLabel: UILabel { var textInsets = UIEdgeInsets.zero { didSet { invalidateIntrinsicContentSize() } } override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect { let insetRect = bounds.inset(by: textInsets) let textRect = super.textRect(forBounds: insetRect, limitedToNumberOfLines: numberOfLines) let invertedInsets = UIEdgeInsets(top: -textInsets.top, left: -textInsets.left, bottom: -textInsets.bottom, right: -textInsets.right) return textRect.inset(by: invertedInsets) } override func drawText(in rect: CGRect) { super.drawText(in: rect.inset(by: textInsets)) } } extension UIViewController { static let DELAY_SHORT = 1.5 static let DELAY_LONG = 3.0 func showToast(_ text: String, delay: TimeInterval = DELAY_LONG) { let label = ToastLabel() label.backgroundColor = UIColor(white: 0, alpha: 0.5) label.textColor = .white label.textAlignment = .center label.font = UIFont.systemFont(ofSize: 15) label.alpha = 0 label.text = text label.clipsToBounds = true label.layer.cornerRadius = 20 label.numberOfLines = 0 label.textInsets = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15) label.translatesAutoresizingMaskIntoConstraints = false view.addSubview(label) let saveArea = view.safeAreaLayoutGuide label.centerXAnchor.constraint(equalTo: saveArea.centerXAnchor, constant: 0).isActive = true label.leadingAnchor.constraint(greaterThanOrEqualTo: saveArea.leadingAnchor, constant: 15).isActive = true label.trailingAnchor.constraint(lessThanOrEqualTo: saveArea.trailingAnchor, constant: -15).isActive = true label.bottomAnchor.constraint(equalTo: saveArea.bottomAnchor, constant: -30).isActive = true UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn, animations: { label.alpha = 1 }, completion: { _ in UIView.animate(withDuration: 0.5, delay: delay, options: .curveEaseOut, animations: { label.alpha = 0 }, completion: {_ in label.removeFromSuperview() }) }) } } 

How to use:

class MyController: UIViewController { override func viewDidLoad() { super.viewDidLoad() showToast("Message") } } 

Other solution

Advantage:

  1. In this version, I don't use a binding to UIViewController

Disadvantages:

  1. After screen rotation, the label does not move.
  2. Does not work correctly with multi-line strings.

Code:

class Helper { static let DELAY_SHORT = 1.5 static let DELAY_LONG = 3.0 static func showToast(_ text: String, delay: TimeInterval = DELAY_LONG) { guard let window = UIApplication.shared.keyWindow else { return } let label = BaseLabel() label.backgroundColor = UIColor(white: 0, alpha: 0.5) label.textColor = .white label.textAlignment = .center label.font = UIFont.systemFont(ofSize: 15) label.alpha = 0 label.text = text label.numberOfLines = 0 var vertical: CGFloat = 0 var size = label.intrinsicContentSize var width = min(size.width, window.frame.width - 60) if width != size.width { vertical = 10 label.textAlignment = .justified } label.textInsets = UIEdgeInsets(top: vertical, left: 15, bottom: vertical, right: 15) size = label.intrinsicContentSize width = min(size.width, window.frame.width - 60) label.frame = CGRect(x: 20, y: window.frame.height - 90, width: width, height: size.height + 20) label.center.x = window.center.x label.layer.cornerRadius = min(label.frame.height/2, 25) label.layer.masksToBounds = true window.addSubview(label) UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn, animations: { label.alpha = 1 }, completion: { _ in UIView.animate(withDuration: 0.5, delay: delay, options: .curveEaseOut, animations: { label.alpha = 0 }, completion: {_ in label.removeFromSuperview() }) }) } } 

How to use:

Helper.showToast("Message") 

2 Comments

You can also add label.heightAnchor.constraint(equalToConstant: 35).active = true to set the view height so the label will leave spacing above and below the text.
Your "other solution" won't compile for me, TimeInterval does not exist, etc.
16

Just add the method below. This will show message in different colors with animation (message appearing from left to right & disappear).

Swift 3.0 -

class Toast { class private func showAlert(backgroundColor:UIColor, textColor:UIColor, message:String) { let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate let label = UILabel(frame: CGRect.zero) label.textAlignment = NSTextAlignment.center label.text = message label.font = UIFont(name: "", size: 15) label.adjustsFontSizeToFitWidth = true label.backgroundColor = backgroundColor //UIColor.whiteColor() label.textColor = textColor //TEXT COLOR label.sizeToFit() label.numberOfLines = 4 label.layer.shadowColor = UIColor.gray.cgColor label.layer.shadowOffset = CGSize(width: 4, height: 3) label.layer.shadowOpacity = 0.3 label.frame = CGRect(x: appDelegate.window!.frame.size.width, y: 64, width: appDelegate.window!.frame.size.width, height: 44) label.alpha = 1 appDelegate.window!.addSubview(label) var basketTopFrame: CGRect = label.frame; basketTopFrame.origin.x = 0; UIView.animate(withDuration :2.0, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.1, options: UIViewAnimationOptions.curveEaseOut, animations: { () -> Void in label.frame = basketTopFrame }, completion: { (value: Bool) in UIView.animate(withDuration:2.0, delay: 2.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.1, options: UIViewAnimationOptions.curveEaseIn, animations: { () -> Void in label.alpha = 0 }, completion: { (value: Bool) in label.removeFromSuperview() }) }) } class func showPositiveMessage(message:String) { showAlert(backgroundColor: UIColor.green, textColor: UIColor.white, message: message) } class func showNegativeMessage(message:String) { showAlert(backgroundColor: UIColor.red, textColor: UIColor.white, message: message) } } 

Comments

13

Swift 5. If you want a simple toast implementation, please find the code below.

extension UIViewController{ func showToast(message : String, seconds: Double){ let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) alert.view.backgroundColor = .black alert.view.alpha = 0.5 alert.view.layer.cornerRadius = 15 self.present(alert, animated: true) DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds) { alert.dismiss(animated: true) } } } 

Call It from UIViewController

 self.showToast(message: "Updating...", seconds: 1.0) 

3 Comments

This is not a toast notification. This is a modal alert.
perfect code, working like charm :)
This is the quick hacky non-toast we deserve
11

What exactly you need is https://github.com/Rannie/Toast-Swift/blob/master/SwiftToastDemo/Toast/HRToast%2BUIView.swift .

Download the HRToast + UIView.swift class and drag and drop to project. Make sure you check 'copy items if needed' on dialogue box.

 //Usage: self.view.makeToast(message: "Simple Toast") self.view.makeToast(message: "Simple Toast", duration: 2.0, position:HRToastPositionTop) self.view.makeToast(message: "Simple Toast", duration: 2.0, position: HRToastPositionCenter, image: UIImage(named: "ic_120x120")!) self.view.makeToast(message: "It is just awesome", duration: 2.0, position: HRToastPositionDefault, title: "Simple Toast") self.view.makeToast(message: "It is just awesome", duration: 2.0, position: HRToastPositionCenter, title: "Simple Toast", image: UIImage(named: "ic_120x120")!) self.view.makeToastActivity() self.view.makeToastActivity(position: HRToastPositionCenter) self.view.makeToastActivity(position: HRToastPositionDefault, message: "Loading") self.view.makeToastActivityWithMessage(message: "Loading") 

1 Comment

how can i change the color of toast.. when i m trying with self.view.hr_setToastThemeColor(color: #ThemeColor) it is giving error
9

I have been using this extension when ever i need toast-message like android.. Just copy the extension to you project and then in your UIViewController class, call the function like

self.toastMessage("Downloading...") // Extention is below extension UIViewController { func toastMessage(_ message: String){ guard let window = UIApplication.shared.keyWindow else {return} let messageLbl = UILabel() messageLbl.text = message messageLbl.textAlignment = .center messageLbl.font = UIFont.systemFont(ofSize: 12) messageLbl.textColor = .white messageLbl.backgroundColor = UIColor(white: 0, alpha: 0.5) let textSize:CGSize = messageLbl.intrinsicContentSize let labelWidth = min(textSize.width, window.frame.width - 40) messageLbl.frame = CGRect(x: 20, y: window.frame.height - 90, width: labelWidth + 30, height: textSize.height + 20) messageLbl.center.x = window.center.x messageLbl.layer.cornerRadius = messageLbl.frame.height/2 messageLbl.layer.masksToBounds = true window.addSubview(messageLbl) DispatchQueue.main.asyncAfter(deadline: .now() + 1) { UIView.animate(withDuration: 1, animations: { messageLbl.alpha = 0 }) { (_) in messageLbl.removeFromSuperview() } } }} 

2 Comments

Don't just blurt out code! Adding some text to describe how this code best answers the question will improve the long-term value of the answer and help to prevent it from being deleted during review.
Code was self explanatory sir but still i edited. If not done correctly please do tell.
6

If the need is for a simple Toast message without fancy customization of font, alignment, text color, etc. then the following would do just fine

let messageVC = UIAlertController(title: "Message Title", message: "Account Created successfully" , preferredStyle: .actionSheet) present(messageVC, animated: true) { Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: { (_) in messageVC.dismiss(animated: true, completion: nil)})} 

.actionSheet presents the alert from Bottom of the screen and the Timer takes care of the display duration. You can add this as an extension to UIViewController and then call it from anywhere.

Comments

4

if makeToast:duration:position: is defined in objective-c and can be called, then the swift code will be

self.view.makeToast("Acount created Successfully", duration: 0.5, position: "bottom") 

You may need to use a bridging header to gain access to those method in your swift code though.

Comments

3

@mr-bean code updated to latest Swift version (3.x)

 let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 150, y: self.view.frame.size.height-100, width: 300, height: 35)) toastLabel.backgroundColor = UIColor.black toastLabel.textColor = UIColor.white toastLabel.textAlignment = NSTextAlignment.center self.view.addSubview(toastLabel) toastLabel.text = message toastLabel.alpha = 1.0 toastLabel.layer.cornerRadius = 10; toastLabel.clipsToBounds = true UIView.animate(withDuration: 4.0, animations: { toastLabel.alpha = 0.0 }) 

Comments

3

I have modified the @samo's answer with:

  • Proper variables name's

  • Leading and Trailing constraints changed to center constraint.

Now message will adjust its width according to message and it will be centred.

extension UIViewController { func showToast(message: String) { let toastContainer = UIView(frame: CGRect()) toastContainer.backgroundColor = UIColor.black.withAlphaComponent(0.6) toastContainer.alpha = 0.0 toastContainer.layer.cornerRadius = 20; toastContainer.clipsToBounds = true let toastLabel = UILabel(frame: CGRect()) toastLabel.textColor = UIColor.white toastLabel.textAlignment = .center; toastLabel.font.withSize(12.0) toastLabel.text = message toastLabel.clipsToBounds = true toastLabel.numberOfLines = 0 toastContainer.addSubview(toastLabel) self.view.addSubview(toastContainer) toastLabel.translatesAutoresizingMaskIntoConstraints = false toastContainer.translatesAutoresizingMaskIntoConstraints = false let centerX = NSLayoutConstraint(item: toastLabel, attribute: .centerX, relatedBy: .equal, toItem: toastContainer, attribute: .centerXWithinMargins, multiplier: 1, constant: 0) let lableBottom = NSLayoutConstraint(item: toastLabel, attribute: .bottom, relatedBy: .equal, toItem: toastContainer, attribute: .bottom, multiplier: 1, constant: -15) let lableTop = NSLayoutConstraint(item: toastLabel, attribute: .top, relatedBy: .equal, toItem: toastContainer, attribute: .top, multiplier: 1, constant: 15) toastContainer.addConstraints([centerX, lableBottom, lableTop]) let containerCenterX = NSLayoutConstraint(item: toastContainer, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0) let containerTrailing = NSLayoutConstraint(item: toastContainer, attribute: .width, relatedBy: .equal, toItem: toastLabel, attribute: .width, multiplier: 1.1, constant: 0) let containerBottom = NSLayoutConstraint(item: toastContainer, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: -75) self.view.addConstraints([containerCenterX,containerTrailing, containerBottom]) UIView.animate(withDuration: 0.5, delay: 0.0, options: .curveEaseIn, animations: { toastContainer.alpha = 1.0 }, completion: { _ in UIView.animate(withDuration: 0.5, delay: 1.5, options: .curveEaseOut, animations: { toastContainer.alpha = 0.0 }, completion: {_ in toastContainer.removeFromSuperview() }) }) } } 

2 Comments

Resizing works nicely but you can't set the font size
toastLabel.font = toastLabel.font.withSize(40)
3
extension UIViewController { func showToast(message:String,color:UIColor) { DispatchQueue.main.async { let toastLbl = UILabel(frame: CGRect(x: 20, y: self.view.frame.size.height - 100, width: self.view.frame.width - 40 , height: 30)) toastLbl.layer.cornerRadius = 8; toastLbl.clipsToBounds = true toastLbl.textColor = .white toastLbl.font = .systemFont(ofSize: 15) toastLbl.textAlignment = .center; toastLbl.text = message self.view.addSubview(toastLbl) toastLbl.backgroundColor = color UIView.animate(withDuration: 2.0, delay: 0, options: .transitionCurlDown, animations: { }, completion: {(isCompleted) in toastLbl.removeFromSuperview() }) } } } 
self.view.showToast(message: "Toast Shown", color: .green) 

1 Comment

For dynamic height based on content: let padding: CGFloat = 8 let maxSize = CGSize(width: self.view.frame.width - 40 - (2 * padding), height: .greatestFiniteMagnitude) let estimatedSize = toastLabel.sizeThatFits(maxSize) toastLabel.frame.size.height = estimatedSize.height + (2 * padding)
2

I know there are accepted answers but they all seem to have a big flaw - if you show several toasts in a short period of time they will show on top of each other. Here is my implementation which takes this problem into consideration:

class Toast: UILabel { private let BOTTOM_MARGIN: CGFloat = 16 private let SIDE_MARGIN: CGFloat = 16 private let HEIGHT: CGFloat = 35 private let SHOW_TIME_SECONDS = TimeInterval(3) private let BACKGROUND_COLOR = UIColor.darkGray.withAlphaComponent(0.7).cgColor private let TEXT_COLOR = UIColor.white private let ANIMATION_DURATION_SEC = 0.33 private static var queue: [ToastHolder] = [] private static var showing: Toast? init(_ text: String) { super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) self.text = text self.textColor = TEXT_COLOR textAlignment = .center self.layer.backgroundColor = BACKGROUND_COLOR self.layer.cornerRadius = 5 } public func show(_ parent: UIViewController) { frame = CGRect(x: SIDE_MARGIN, y: UIScreen.main.bounds.height - BOTTOM_MARGIN - HEIGHT, width: UIScreen.main.bounds.width - 2 * SIDE_MARGIN, height: HEIGHT) if Toast.showing == nil { Log.d("showing \(String(describing: text))") Toast.showing = self alpha = 0 parent.view.addSubview(self) UIView.animate(withDuration: ANIMATION_DURATION_SEC, animations: { self.alpha = 1 }, completion: { (completed) in Timer.scheduledTimer(timeInterval: self.SHOW_TIME_SECONDS, target: self, selector: #selector(self.onTimeout), userInfo: nil, repeats: false) }) } else { Toast.queue.append(ToastHolder(self, parent)) } } @objc func onTimeout() { UIView.animate(withDuration: ANIMATION_DURATION_SEC, animations: { self.alpha = 0 }, completion: { (completed) in Toast.showing = nil self.removeFromSuperview() if !Toast.queue.isEmpty { let holder = Toast.queue.removeFirst() holder.toast.show(holder.parent) } }) } required init?(coder aDecoder: NSCoder) { fatalError("this initializer is not supported") } private class ToastHolder { let toast: Toast let parent: UIViewController init(_ t: Toast, _ p: UIViewController) { toast = t parent = p } } } 

Usage:

Toast("my message").show(self) 

Hope it helps someone.

1 Comment

This is Nice w/ the Queuing of messages one after another to show! Although the solution from stackoverflow.com/a/50710991/14414215 has the auto-layout and auto-wrapping of a long message.
2

How about use Toaster

At a Glance

Toast(text: "Hello, world!").show() 

Setting delay and duration

Toast(text: "Hello, world!", duration: Delay.long) Toast(text: "Hello, world!", delay: Delay.short, duration: Delay.long) 

Removing Toast

let toast = Toast(text: "Hello") toast.show() toast.cancel() // remove toast immediately 

Customizing Appearance

  • backgroundColor
  • cornerRadius
  • textInsets
  • textColor
  • font
  • bottomOffsetPortrait
  • bottomOffsetLandscape
  • shadowPath
  • shadowColor
  • shadowOpacity
  • shadowOffset
  • shadowRadius
  • maxWidthRatio
  • useSafeAreaForBottomOffset

Comments

1

Instead of using UILabel using UITextView gets better results.

func showToast(message: String) { let toastLabel = UITextView(frame: CGRect(x: self.view.frame.size.width/16, y: self.view.frame.size.height-150, width: self.view.frame.size.width * 7/8, height: 35)) toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6) toastLabel.textColor = UIColor.white toastLabel.textAlignment = .center; toastLabel.text = " \(message) " toastLabel.alpha = 1.0 toastLabel.layer.cornerRadius = 10; toastLabel.clipsToBounds = true toastLabel.font = UIFont(name: (toastLabel.font?.fontName)!, size: 16) toastLabel.layoutEdgeInsets.left = 8 toastLabel.layoutEdgeInsets.right = 8 toastLabel.center.x = self.view.frame.size.width/2 self.view.addSubview(toastLabel) UIView.animate(withDuration: 5.0, delay: 0.1, options: .curveEaseOut, animations: { toastLabel.alpha = 0.0 }, completion: {(isCompleted) in toastLabel.removeFromSuperview() }) } 

Space is added with message to provide good spacing at the both ends so that it looks good. Modified version of answer of Mr.Bean

Comments

1

Step 1: Create a new Swift file for your custom toast view:

class ToastView: UIView { private var messageLabel: UILabel! init(message: String) { super.init(frame: CGRect.zero) configureUI(message: message) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } private func configureUI(message: String) { // Customize your toast view's appearance backgroundColor = UIColor.black.withAlphaComponent(0.8) layer.cornerRadius = 10 clipsToBounds = true messageLabel = UILabel(frame: CGRect.zero) messageLabel.text = message messageLabel.textColor = UIColor.white messageLabel.numberOfLines = 0 messageLabel.textAlignment = .center messageLabel.font = UIFont.systemFont(ofSize: 15) addSubview(messageLabel) messageLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ messageLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8), messageLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16), messageLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), messageLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8) ]) } } 

Step 2: To show the toast message, add the following extension to UIViewController:

extension UIViewController { func showToast(message: String, duration: TimeInterval = 2.0) { let toastView = ToastView(message: message) view.addSubview(toastView) toastView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ toastView.centerXAnchor.constraint(equalTo: view.centerXAnchor), toastView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -50), toastView.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 20), toastView.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -20) ]) DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + duration) { UIView.animate(withDuration: 0.3, animations: { toastView.alpha = 0 }, completion: { _ in toastView.removeFromSuperview() }) } } } 

Step 3: Now, in your view controller, you can use the showToast method to display the toast message:

// Example usage in your UIViewController: class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Call the showToast method to display a toast message showToast(message: "Hello, this is a toast message!") } } 

Comments

0
static func popUp(context ctx: UIViewController, msg: String) { let toast = UILabel(frame: CGRect(x: 16, y: ctx.view.frame.size.height / 2, width: ctx.view.frame.size.width - 32, height: 100)) toast.backgroundColor = UIColor.lightGray toast.textColor = UIColor.white toast.textAlignment = .center; toast.numberOfLines = 3 toast.font = UIFont.systemFont(ofSize: 20) toast.layer.cornerRadius = 12; toast.clipsToBounds = true toast.text = msg ctx.view.addSubview(toast) UIView.animate(withDuration: 5.0, delay: 0.2, options: .curveEaseOut, animations: { toast.alpha = 0.0 }, completion: {(isCompleted) in toast.removeFromSuperview() }) } 

Then just call it from UIViewController

popUp(context: self, msg: "Your message") 

Comments

0

Let me add this to this chain of answers: This library does what you need DCToastView allowing you to provide toast messages from the top or bottom side of the screen:

DCToastViewSample

You will just need to add the pod

pod 'DCToastView'

Import it where you want to use it.

import DCToastView

And use it

ToastPresenter.shared.show(in: self.view, message: "This is a toast")

You can pass the following properties to the show method:

  • view: The view in which the toast is going to be presented
  • message: The message that the toast will show
  • toastPlace: The place which can be .down or .up
  • backgroundColor: The background color of the toast; defaults to black
  • textColor: The text color of the message; defaults to white
  • timeOut: The amount of seconds for the toast to dismiss if not provided it means that the toast will be sticky (will remain until touched); defaults to nil
  • roundness: How round the toast will be: .none, .low, .mid, .high; defaults to .mid

Comments

0

This will help for you it will make the toast at the center with proper padding

func showToast(message:String,view:UIView){ let toastLabel = PaddingLabel() toastLabel.frame = CGRect(x:0, y: view.frame.size.height-100, width: view.frame.width-50, height: 0) toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6) toastLabel.textColor = UIColor.white toastLabel.textAlignment = .center; toastLabel.font = UIFont(name: "Montserrat-Light", size: 12.0) toastLabel.text = message toastLabel.alpha = 1.0 toastLabel.layer.cornerRadius = 10; toastLabel.clipsToBounds = true toastLabel.sizeToFit() toastLabel.frame.origin.x=(view.frame.width/2)-(toastLabel.frame.width/2) view.addSubview(toastLabel) UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: { toastLabel.alpha = 0.0 }, completion: {(isCompleted) in toastLabel.removeFromSuperview() }) } 

And add this PaddingLabel file for label padding

import Foundation import UIKit class PaddingLabel: UILabel { let padding=UIEdgeInsetsMake(5, 10, 5,10) override func drawText(in rect: CGRect) { super.drawText(in: UIEdgeInsetsInsetRect(rect, padding)) } override func sizeThatFits(_ size: CGSize) -> CGSize { let superSizeThatFits=super.sizeThatFits(size) let width=superSizeThatFits.width+padding.left+padding.right let height=superSizeThatFits.height+padding.top+padding.bottom return CGSize(width: width, height: height) } } 

Comments

0

Mr. Beans answer works well. However, his answer uses a small width & isn't multi-line friendly. Use this instead.

func showToastFaded(message : String) { let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 125, y: self.view.frame.size.height-100, width: 250, height: 35)) toastLabel.numberOfLines = 0 toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6) toastLabel.textColor = UIColor.white toastLabel.textAlignment = .center; toastLabel.text = message toastLabel.alpha = 1.0 toastLabel.layer.cornerRadius = 10; toastLabel.clipsToBounds = true toastLabel.sizeToFit() toastLabel.frame = CGRect( x: toastLabel.frame.minX, y: toastLabel.frame.minY,width: toastLabel.frame.width + 20, height: toastLabel.frame.height + 8) self.view.addSubview(toastLabel) UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: { toastLabel.alpha = 0.0 }, completion: {(isCompleted) in toastLabel.removeFromSuperview() }) } 

Comments

0

The best and easiest way to add a toast on an iOS app is using this library called Loafjet. The library is really small(27kb), won't make much difference to your project. Try it!

1 Comment

Agreed, but it depends on the developer how they adapt it, if they want then they can even refer from the code given in the library and try implementing it. Libraries are not only meant to use directly, they can even be used to learn new stuffs :)
0

I changed @Samo answer. Here it is, mine, quite simple. This is also landscape and long text friendly.

Toast.show(message: "Hello Toast", on: view) 

..

class Toast { static func show(message: String, on baseView: UIView) { let containerView = UIView() containerView.backgroundColor = .black.withAlphaComponent(0.6) containerView.alpha = 0 containerView.layer.cornerRadius = 25 containerView.clipsToBounds = true let toastLabel = UILabel() toastLabel.textColor = .white toastLabel.textAlignment = .center toastLabel.font.withSize(12.0) toastLabel.text = message toastLabel.clipsToBounds = true toastLabel.numberOfLines = 0 baseView.addSubview(containerView) containerView.translatesAutoresizingMaskIntoConstraints = false containerView.leadingAnchor.constraint(greaterThanOrEqualTo: baseView.leadingAnchor, constant: 65).isActive = true containerView.trailingAnchor.constraint(lessThanOrEqualTo: baseView.trailingAnchor, constant: -65).isActive = true containerView.bottomAnchor.constraint(equalTo: baseView.safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true containerView.centerXAnchor.constraint(equalTo: baseView.centerXAnchor).isActive = true containerView.addSubview(toastLabel) toastLabel.translatesAutoresizingMaskIntoConstraints = false toastLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 15).isActive = true toastLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 15).isActive = true toastLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -15).isActive = true toastLabel.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -15).isActive = true UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn, animations: { containerView.alpha = 1 }, completion: { _ in UIView.animate(withDuration: 0.5, delay: 1.5, options: .curveEaseOut, animations: { containerView.alpha = 0 }, completion: { _ in containerView.removeFromSuperview() }) }) } } 

Comments

0

This is another way to do it.

 func showToast(viewController: UIViewController?, message: String) { let alertDisapperTimeInSeconds = 3.0 let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 75, y: self.view.frame.size.height-100, width: 150, height: 35)) toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6) toastLabel.textColor = UIColor.white toastLabel.font = .systemFont(ofSize: 14) toastLabel.textAlignment = .center; toastLabel.text = message toastLabel.alpha = 1.0 toastLabel.layer.cornerRadius = 10; toastLabel.clipsToBounds = true viewController?.view.addSubview(toastLabel) DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + alertDisapperTimeInSeconds) { toastLabel.alpha = 0.0 toastLabel.removeFromSuperview() } } 

How to access function

self.showToast(viewController: self, message: "I am a Toast Message") 

Comments

-1

Swift 4.2 Very easy and super way

let toastLabel = UILabel() toastLabel.lineBreakMode = .byWordWrapping toastLabel.numberOfLines = 0 toastLabel.text = "Type your message you want to show in toast" toastLabel.sizeToFit() //MARK Resize the Label Frame toastLabel.frame = CGRect(x: toastLabel.frame.origin.x, y: toastLabel.frame.origin.y, width: toastLabel.frame.size.width + 40, height: toastLabel.frame.size.height + 40) self.view.addSubview(toastLabel) 

Comments

-1

Here is my solution. Hope it helps for someone..

class Toasty { static let DELAY_SHORT = 2.0 static let DELAY_LONG = 4.0 static let BG_OPACITY: Double = 0.9 static let TOAST_HEIGHT = 20 static let TOAST_WIDTH = 24 static let TOAST_ADJUSTMENT = 96 static let FONT_SIZE = 16 enum Gravity { case bottom case center case top } enum Delay { case short case long } static func showToast(_ message: String, _ txtColor: UIColor, _ bgColor: UIColor, _ position: Gravity, _ delay: Delay) { guard let window = UIApplication.shared.keyWindow else { return } let label = ToastyLabel() label.textColor = txtColor label.backgroundColor = bgColor label.textAlignment = .center label.font = UIFont.systemFont(ofSize: CGFloat(FONT_SIZE)) label.alpha = 0 label.text = message label.numberOfLines = 0 var vertical: CGFloat = 0 var size = label.intrinsicContentSize var width = min(size.width, window.frame.width - 60) if width != size.width { vertical = 1000 label.textAlignment = .justified } label.textInsets = UIEdgeInsets(top: vertical, left: 15, bottom: vertical, right: 15) size = label.intrinsicContentSize width = min(size.width, window.frame.width - 60) if (position == Gravity.bottom) { label.frame = CGRect(x: CGFloat(TOAST_WIDTH), y: window.frame.height - CGFloat(TOAST_ADJUSTMENT), width: width, height: size.height + CGFloat(TOAST_HEIGHT)) } else if (position == Gravity.center) { label.frame = CGRect(x: CGFloat(TOAST_WIDTH), y: window.frame.height / 2, width: width, height: size.height + CGFloat(TOAST_HEIGHT)) } else if (position == Gravity.top) { label.frame = CGRect(x: CGFloat(TOAST_WIDTH), y: CGFloat(TOAST_ADJUSTMENT), width: width, height: size.height + CGFloat(TOAST_HEIGHT)) } label.center.x = window.center.x label.layer.cornerRadius = min(label.frame.height / 2, 32) label.layer.masksToBounds = true window.addSubview(label) UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn, animations: { label.alpha = 1 }, completion: { _ in UIView.animate(withDuration: 0.5, delay: delay == Delay.long ? DELAY_LONG : DELAY_SHORT, options: .curveEaseOut, animations: { label.alpha = 0 }, completion: {_ in label.removeFromSuperview() }) }) } class func regular(msg: String, position: Gravity, delay: Delay) { showToast(msg, UIColor(.white), UIColor(.black.opacity(BG_OPACITY)), position, delay) } class func info(msg: String, position: Gravity, delay: Delay) { showToast(String("\u{24D8}")+" "+msg, UIColor.white, UIColor(Color(red: 0/255, green: 100/255, blue: 225/255).opacity(BG_OPACITY)), position, delay) } class func alert(msg: String, position: Gravity, delay: Delay) { showToast(String("\u{26A0}")+" "+msg, UIColor.black, UIColor(Color(red: 255/255, green: 175/255, blue: 0/255).opacity(BG_OPACITY)), position, delay) } class func success(msg: String, position: Gravity, delay: Delay) { showToast(String("\u{2705}")+" "+msg, UIColor.white, UIColor(Color(red: 0/255, green: 150/255, blue: 0/255).opacity(BG_OPACITY)), position, delay) } class func error(msg: String, position: Gravity, delay: Delay) {//2757 showToast(String("\u{274C}")+" "+msg, UIColor.white, UIColor(Color(red: 175/255, green: 0/255, blue: 0/255).opacity(BG_OPACITY)), position, delay) } } class ToastyLabel: UILabel { var textInsets = UIEdgeInsets.zero { didSet { invalidateIntrinsicContentSize() } } override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect { let insetRect = bounds.inset(by: textInsets) let textRect = super.textRect(forBounds: insetRect, limitedToNumberOfLines: numberOfLines) let invertedInsets = UIEdgeInsets(top: -textInsets.top, left: -textInsets.left, bottom: -textInsets.bottom, right: -textInsets.right) return textRect.inset(by: invertedInsets) } override func drawText(in rect: CGRect) { super.drawText(in: rect.inset(by: textInsets)) } } 

Usage:

@State var increment = 0 ZStack { Button(action: { increment += 1 if increment == 1 { Toasty.info(msg: "Info Toasty", position: .bottom, delay: .short) } else if increment == 2 { Toasty.alert(msg: "Alert Toasty", position: .top, delay: .short) } else if increment == 3 { Toasty.success(msg: "Success Toasty", position: .center, delay: .short) } else if increment == 4 { Toasty.error(msg: "Error Toasty", position: .bottom, delay: .short) } else if increment == 5 { Toasty.regular(msg: "Regular Toasty", position: .top, delay: .short) increment = 0 } }, label: { Text("Show Toasty") .padding(12) .background(RoundedRectangle(cornerRadius: 8) .stroke(Color.blue, lineWidth: 1)) })} 

Toasty.gif

3 Comments

What's ToastLabel? It's used in your code, but has no definition. I guess should be ToastyLabel, right?
The code also must have both UIKit and SwiftUI imported in order to compile successfully.
@lazarevzubov, yes it is ToastyLabel (typo error) and import SwiftUI to work on it. Sorry and Thank you for point out.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.