JSToast
is fully customizable toast package.
- iOS 14.0+
dependencies: [
.package(url: "https://github.com/wlsdms0122/JSToast.git", from: "2.0.0")
]
To display a toast, you first need to create a view. This view is created using the Toast
initializer and will be used to display the toast message.
let toastView = UILabel()
toastView.backgroundColor = .black.withAlphaComponent(0.6)
toastView.text = "Hello World!"
toastView.textColor = .white
let toast = Toast(toastView)
⚠️ It is recommended that the toast view has its own size.
Once you have defined a toast, you can display or hide it on the screen using the show function.
toast.show(
withDuration: 3,
layouts: [
.center(of: .x),
.inside(of: .bottom, of: button, offset: 16)
]
)
The show function has many optional parameters, but most of them have default values. This makes it easy to display a toast message with just a few lines of code.
JSToast
offers multiple layout types for positioning your toast messages. These layouts include options to position the toast inside or outside a target view, or to center it along a specific axis.
Below are the available layout methods.
extension Layout {
/// Positions the toast inside the specified anchor of the target view.
static func inside(_ anchor: Anchor, of target: UIView? = nil, offset: CGFloat = 0, ignoresSafeArea: Bool = false) -> Self
/// Positions the toast outside the specified anchor of the target view.
static func outside(_ anchor: Anchor, of target: UIView? = nil, offset: CGFloat = 0) -> Self
/// Centers the toast along the specified axis of the target view.
static func center(_ axis: Axis, of target: UIView? = nil, offset: CGFloat = 0, ignoresSafeArea: Bool = false) -> Self
/// Sets a fixed width for the toast.
static func width(_ width: CGFloat) -> Self
/// Sets a fixed height for the toast.
static func height(_ height: CGFloat) -> Self
}
When specifying a layout, the target
parameter determines the view relative to which the toast will be positioned. If the target
parameter is not specified (i.e., set to nil), the toast will reference its layer
for positioning. If the layer
is also nil, the toast will default to referencing the window
for its positioning.
By using inside
or outside
layouts with the target
parameter, you can position the toast relative to a specific view.
toast.show(
withDuration: 3,
layouts: [
.center(of: .x),
.outside(of: .top, of: button, offset: 16)
]
)
JSToast
allows you to set default animations or create custom animations for controlling how the toast appears and disappears from the screen. The showAnimation
and hideAnimation
parameters of the show function are used to define these animations.
extension ToastAnimation {
static func fadeIn(duration: TimeInterval, curve: UIView.AnimationCurve = .easeInOut) -> Self
static func fadeOut(duration: TimeInterval, curve: UIView.AnimationCurve = .easeInOut) -> Self
static func slideIn(duration: TimeInterval, direction: Direction, curve: UIView.AnimationCurve = .easeInOut, offset: CGFloat? = nil) -> Self
static func slideOut(duration: TimeInterval, direction: Direction, curve: UIView.AnimationCurve = .easeInOut, offset: CGFloat? = nil) -> Self
}
You can easily apply animations to your toast messages.
Below is an example where a toast slides in from left and out to the right.
toast.show(
withDuration: 3,
layouts: [
.center(.x),
.outside(.bottom, of: button, offset: 16)
],
showAnimation: .slideIn(duration: 0.3, direction: .right),
hideAnimation: .slideOut(duration: 0.3, direction: .right)
)
If you want to create a custom animation, you can implement the ToastAnimation
protocol. This requires the implementation of two functions.
protocol ToastAnimation {
func play(_ view: UIView, completion: @escaping (Bool) -> Void)
func cancel(completion: @escaping () -> Void)
}
To create custom animations, reference the default animations for guidance.
While the Toast
class can be used on its own, creating a custom manager like Toaster
can be more beneficial for performing complex tasks or limiting operations within your application.
Toaster
is a custom class that manages Toast
instances to ensure that only one toast is visible at a time. This enhances the user experience by preventing multiple toasts from being displayed simultaneously.
By implementing a custom manager like Toaster
, developers can control the behavior of toasts within their application, allowing for the creation of custom workflows that best suit their project's requirements.
JSToast
supports SwiftUI
through the ToastReader
component. While the interface provided is similar to the UIKit
version, it is implemented in a way that is more suitable for SwiftUI
.
struct SampleView: View {
var body: some View {
ToastReader { toaster in
Button("Show Toast") {
isShow = true
}
.toastTarget("button")
.onChange(of: isShow) { isShow in
if isShow {
toaster.show(
withDuration: 3,
layouts: [
.center(.x),
.outside(.bottom, offset: 16)
],
target: "button"
) {
Text("Hello World")
.foregroundStyle(.white)
.background(.black.opacity(0.6))
}
} else {
toaster.hide()
}
}
}
}
@State
var isShow: Bool = false
}
If you want the toast to be part of a specific view hierarchy rather than appearing at the top level (window), you can use ToastLayer
. This allows you to manage the positioning of the toast within a particular part of your view hierarchy.
struct SampleView: View {
var body: some View {
ToastReader { toaster in
ToastLayer("toastLayer") {
Button("Show Toast") {
isShow = true
}
.toastTarget("button")
}
.onChange(of: isShow) { isShow in
if isShow {
toaster.show(
withDuration: 3,
layouts: [
.center(.x),
.outside(.bottom, offset: 16)
],
target: "button",
layer: "toastLayer"
) {
Text("Hello World")
.foregroundStyle(.white)
.background(.black.opacity(0.6))
}
} else {
toaster.hide()
}
}
}
}
@State
var isShow: Bool = false
}
You can also easily display a .toast()
using the toast view modifier. For more details, check out the code examples.
Any ideas, issues, opinions are welcome.
JSToast
is available under the MIT license.