| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- import SwiftUI
- struct Popup<T: View>: ViewModifier {
- let popup: T
- let isPresented: Bool
- let alignment: Alignment
- let direction: Direction
- init(isPresented: Bool, alignment: Alignment, direction: Direction, @ViewBuilder content: () -> T) {
- self.isPresented = isPresented
- self.alignment = alignment
- self.direction = direction
- popup = content()
- }
- func body(content: Content) -> some View {
- content
- .overlay(popupContent())
- }
- @ViewBuilder private func popupContent() -> some View {
- GeometryReader { geometry in
- if isPresented {
- popup
- .animation(.spring())
- .transition(.offset(x: 0, y: direction.offset(popupFrame: geometry.frame(in: .global))))
- .frame(width: geometry.size.width, height: geometry.size.height, alignment: alignment)
- }
- }
- }
- }
- private extension GeometryProxy {
- var belowScreenEdge: CGFloat {
- UIScreen.main.bounds.height - frame(in: .global).minY
- }
- }
- extension Popup {
- enum Direction {
- case top
- case bottom
- func offset(popupFrame: CGRect) -> CGFloat {
- switch self {
- case .top:
- let aboveScreenEdge = -popupFrame.maxY
- return aboveScreenEdge
- case .bottom:
- let belowScreenEdge = UIScreen.main.bounds.height - popupFrame.minY
- return belowScreenEdge
- }
- }
- }
- }
- extension View {
- func popup<T: View>(
- isPresented: Bool,
- alignment: Alignment = .center,
- direction: Popup<T>.Direction = .bottom,
- @ViewBuilder content: () -> T
- ) -> some View {
- modifier(Popup(isPresented: isPresented, alignment: alignment, direction: direction, content: content))
- }
- }
|