[SwiftUI] How to create Toast View
Published: 2022-07-16 03:23:25


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c2v7ku2m11dzijmtpb1y.jpg)
## How to use

```
struct ContentView: View {
    @State var presentTop: Bool = false
    
    var body: some View {
        VStack {
            TPButton(title: "☝️", action: {
                presentTop = true
            })
        }
        .navigationBarTitleDisplayMode(.inline) // if it's needed
        .toast(isPresented: $presentTop, edge: .top) { toastContent }
    }
    
    var toastContent: some View {
        HStack {
            Image(systemName: "checkmark.circle").font(.headline)
            Text("Toast!").font(.headline)
        }
        .frame(maxHeight: .infinity)
        .padding()
        .background(RoundedRectangle(cornerRadius: 8.0).foregroundColor(.random)) // set color whatever you want
    }
```

---


## 3 Steps

1. Create ToastView
2. Create ViewModifier
3. Create ViewModifier


**Step1: Create ToastView**
```
struct Toast<Content:View>: View {
    @Binding var isPresented: Bool
    @State var edge: Edge
    var content: Content
    let action: (() -> Void)?
    
    private var alignment: Alignment {
        switch edge {
        case .top: return .top
        case .leading: return .leading
        case .bottom: return .bottom
        case .trailing: return .trailing
        }
    }
    
    init(isPresented: Binding<Bool>, edge: Edge, action: (() -> Void)? = nil, @ViewBuilder content: () -> Content) {
        _isPresented = isPresented
        _edge = State(wrappedValue: edge)
        self.action = action
        self.content = content()
    }
    
    var body: some View {
        ZStack(alignment: alignment) {
            Spacer().frame(maxWidth: .infinity, maxHeight: .infinity)
            content
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .padding()
        .animation(.spring(), value: isPresented)
        .transition(.move(edge: edge).combined(with: .opacity))
        .onTapGesture {
            withAnimation {
                isPresented = false
                action?()
            }
        }
    }
}
```

**Step2: Create ViewModifier**
```
struct ToastModifier<ToastContent: View>: ViewModifier {
    
    @Binding var isPresented: Bool
    var toast: Toast<ToastContent>
    
    init(isPresented: Binding<Bool>, edge: Edge, action: (() -> Void)? = nil, @ViewBuilder toastContent: () -> ToastContent) {
        _isPresented = isPresented
        toast = Toast(isPresented: isPresented, edge: edge, action: action, content: toastContent)
    }
    
    public func body(content: Content) -> some View {
        ZStack {
            content
            if isPresented { toast }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.clear.ignoresSafeArea(.all, edges: .all))
        .animation(.spring(), value: isPresented)
    }
}
```

**Step3: View Extension**
```
public extension View {
    func toast<Content:View>(isPresented: Binding<Bool>, edge: Edge, action: (() -> Void)? = nil, @ViewBuilder content: () -> Content) -> some View {
        self.modifier(ToastModifier(isPresented: isPresented, edge: edge, action: action, toastContent: content))
    }
}
```