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"];
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"];
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))
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()
})
})
}
}
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)
}
}
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+)
I have two more solutions on Swift 5:
Best solution (in my opinion)
Advantage:
Disadvantages:
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:
UIViewController
Disadvantages:
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")
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)
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")
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()
}
}
}}
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.
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.
@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
})
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()
})
})
}
}
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.
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
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
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)
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")
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:
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:
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)
}
}
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()
})
}
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!
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()
})
})
}
}
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")
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 = ToastLabel()
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))
})}
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!")
}
}
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)