Introduction
iOS has no built-in Toast equivalent. The closest native approach is a UIAlertController with a timer that dismisses it automatically, but this is modal and blocks interaction. The idiomatic iOS alternatives are: a temporary UILabel overlay that fades out (custom Toast view), a third-party library like SwiftMessages or JDStatusBarNotification, or in SwiftUI, a custom .overlay() modifier with animation. For the most common case, a custom Toast view class that adds a label to the window and animates it away is the simplest solution.
Method 1: Custom Toast View (UIKit)
1import UIKit
2
3extension UIViewController {
4 func showToast(message: String, duration: Double = 2.0) {
5 let toastLabel = UILabel()
6 toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.7)
7 toastLabel.textColor = .white
8 toastLabel.textAlignment = .center
9 toastLabel.font = UIFont.systemFont(ofSize: 14)
10 toastLabel.text = message
11 toastLabel.alpha = 0
12 toastLabel.layer.cornerRadius = 10
13 toastLabel.clipsToBounds = true
14 toastLabel.numberOfLines = 0
15
16 let maxWidth = view.frame.width - 40
17 let textSize = toastLabel.sizeThatFits(CGSize(width: maxWidth, height: .greatestFiniteMagnitude))
18 let width = min(textSize.width + 40, maxWidth)
19 let height = textSize.height + 20
20
21 toastLabel.frame = CGRect(
22 x: (view.frame.width - width) / 2,
23 y: view.frame.height - 120,
24 width: width,
25 height: height
26 )
27
28 view.addSubview(toastLabel)
29
30 UIView.animate(withDuration: 0.3, animations: {
31 toastLabel.alpha = 1
32 }) { _ in
33 UIView.animate(withDuration: 0.3, delay: duration, options: [], animations: {
34 toastLabel.alpha = 0
35 }) { _ in
36 toastLabel.removeFromSuperview()
37 }
38 }
39 }
40}
41
42// Usage
43showToast(message: "Item saved successfully")
44showToast(message: "Network error", duration: 3.0)
Method 2: SwiftUI Toast
1import SwiftUI
2
3struct ToastModifier: ViewModifier {
4 @Binding var isShowing: Bool
5 let message: String
6 let duration: Double
7
8 func body(content: Content) -> some View {
9 ZStack(alignment: .bottom) {
10 content
11
12 if isShowing {
13 Text(message)
14 .padding(.horizontal, 16)
15 .padding(.vertical, 10)
16 .background(Color.black.opacity(0.7))
17 .foregroundColor(.white)
18 .cornerRadius(10)
19 .padding(.bottom, 50)
20 .transition(.opacity)
21 .onAppear {
22 DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
23 withAnimation {
24 isShowing = false
25 }
26 }
27 }
28 }
29 }
30 .animation(.easeInOut(duration: 0.3), value: isShowing)
31 }
32}
33
34extension View {
35 func toast(isShowing: Binding<Bool>, message: String, duration: Double = 2.0) -> some View {
36 modifier(ToastModifier(isShowing: isShowing, message: message, duration: duration))
37 }
38}
39
40// Usage
41struct ContentView: View {
42 @State private var showToast = false
43
44 var body: some View {
45 VStack {
46 Button("Show Toast") {
47 showToast = true
48 }
49 }
50 .toast(isShowing: $showToast, message: "Item saved!")
51 }
52}
Method 3: UIAlertController with Auto-Dismiss
1func showAutoAlert(message: String, seconds: Double = 1.5) {
2 let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
3 present(alert, animated: true)
4
5 DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
6 alert.dismiss(animated: true)
7 }
8}
9
10// Usage
11showAutoAlert(message: "Copied to clipboard")
This is the quickest approach but is modal — it dims the background and blocks user interaction until dismissed.
Method 4: Status Bar Notification
1// Using a status bar-style notification (top of screen)
2extension UIViewController {
3 func showStatusBarToast(message: String, duration: Double = 2.0) {
4 guard let window = view.window else { return }
5
6 let banner = UIView()
7 banner.backgroundColor = UIColor.systemGreen
8 banner.frame = CGRect(x: 0, y: -60, width: window.frame.width, height: 60)
9
10 let label = UILabel()
11 label.text = message
12 label.textColor = .white
13 label.textAlignment = .center
14 label.font = UIFont.boldSystemFont(ofSize: 14)
15 label.frame = CGRect(x: 16, y: 20, width: banner.frame.width - 32, height: 30)
16
17 banner.addSubview(label)
18 window.addSubview(banner)
19
20 UIView.animate(withDuration: 0.3, animations: {
21 banner.frame.origin.y = 0
22 }) { _ in
23 UIView.animate(withDuration: 0.3, delay: duration, animations: {
24 banner.frame.origin.y = -60
25 }) { _ in
26 banner.removeFromSuperview()
27 }
28 }
29 }
30}
Android Toast for Reference
// Android — one line
Toast.makeText(context, "Item saved", Toast.LENGTH_SHORT).show()
Common Pitfalls
Using UIAlertController as a Toast replacement: UIAlertController is modal — it blocks user interaction and dims the background, which is the opposite of Toast behavior. Use a non-modal overlay view instead.
Adding the Toast to the view controller's view instead of the window: If the view controller transitions or is dismissed while the Toast is visible, the Toast disappears too. Adding to the UIWindow ensures the Toast outlives navigation transitions.
Not removing the Toast label from the superview after animation: Forgetting toastLabel.removeFromSuperview() in the completion handler causes invisible views to accumulate in the view hierarchy, leaking memory over time.
Hardcoding Toast position without accounting for safe areas: On devices with notches (iPhone X+), a Toast at y = view.frame.height - 100 may overlap with the home indicator. Use view.safeAreaInsets.bottom to position correctly.
Showing multiple Toasts simultaneously without a queue: If the user triggers multiple Toasts quickly, they stack on top of each other. Implement a queue that waits for the current Toast to dismiss before showing the next one, or cancel the current Toast and show the new one.
Summary
iOS has no built-in Toast — use a custom UILabel overlay with fade animation for the closest equivalent
In SwiftUI, use a custom ViewModifier with @Binding and onAppear auto-dismiss
Avoid UIAlertController for Toast-like behavior — it blocks user interaction
Add Toasts to the UIWindow to survive view controller transitions
Account for safe areas and queue multiple Toasts to avoid stacking