-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
168 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,15 @@ | ||
// swift-tools-version: 5.6 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
// swift-tools-version:5.1 | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "FullScreenOverlay", | ||
platforms: [.iOS(.v13), .macOS(.v10_15), .tvOS(.v13), .watchOS(.v6)], | ||
products: [ | ||
// Products define the executables and libraries a package produces, and make them visible to other packages. | ||
.library( | ||
name: "FullScreenOverlay", | ||
targets: ["FullScreenOverlay"]), | ||
], | ||
dependencies: [ | ||
// Dependencies declare other packages that this package depends on. | ||
// .package(url: /* package url */, from: "1.0.0"), | ||
.library(name: "FullScreenOverlay", targets: ["FullScreenOverlay", "Previews"]) | ||
], | ||
targets: [ | ||
// Targets are the basic building blocks of a package. A target can define a module or a test suite. | ||
// Targets can depend on other targets in this package, and on products in packages this package depends on. | ||
.target( | ||
name: "FullScreenOverlay", | ||
dependencies: []), | ||
.testTarget( | ||
name: "FullScreenOverlayTests", | ||
dependencies: ["FullScreenOverlay"]), | ||
.target(name: "FullScreenOverlay", dependencies: []), | ||
.target(name: "Previews", dependencies: ["FullScreenOverlay"]) | ||
] | ||
) |
This file was deleted.
Oops, something went wrong.
17 changes: 17 additions & 0 deletions
17
Sources/FullScreenOverlay/FullScreenOverlayContainer.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import SwiftUI | ||
|
||
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) | ||
class FullScreenOverlayContainer: ObservableObject { | ||
|
||
static let shared: FullScreenOverlayContainer = .init() | ||
|
||
@Published private(set) var overlays: [PresentationSpace: [AnyHashable: AnyView]] = .init() | ||
|
||
func updateOverlay<ID: Hashable, Overlay: View>(_ overlay: Overlay, for id: ID, in presentationSpace: PresentationSpace) { | ||
self.overlays[presentationSpace, default: [:]].updateValue(AnyView(overlay), forKey: id) | ||
} | ||
|
||
func removeOverlay<ID: Hashable>(for id: ID, in presentationSpace: PresentationSpace) { | ||
self.overlays[presentationSpace, default: [:]].removeValue(forKey: id) | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
Sources/FullScreenOverlay/FullScreenOverlayPresenter.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import SwiftUI | ||
|
||
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) | ||
struct FullScreenOverlayPresenter: ViewModifier { | ||
|
||
var presentationSpace: PresentationSpace | ||
|
||
@ObservedObject private var container: FullScreenOverlayContainer = .shared | ||
|
||
func body(content: Content) -> some View { | ||
content.overlay( | ||
ZStack { | ||
ForEach( | ||
container.overlays[presentationSpace, default: [:]].sorted(by: { $0.key.hashValue < $1.key.hashValue }), | ||
id: \.key | ||
) { _, overlay in | ||
overlay | ||
} | ||
} | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import SwiftUI | ||
|
||
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) | ||
struct FullScreenOverlaySetter<Overlay: View>: ViewModifier { | ||
|
||
var overlay: Overlay | ||
var presentationSpace: PresentationSpace | ||
|
||
@State private var id: UUID = .init() | ||
@State private var isAppearing: Bool = false | ||
|
||
func body(content: Content) -> some View { | ||
return content | ||
.onAppear { isAppearing = true; updateOverlay() } | ||
.onDisappear { isAppearing = false; removeOverlay() } | ||
.onUpdate { isAppearing ? updateOverlay() : removeOverlay() } | ||
// onDisappear 이후에 onUpdate가 실행되는 경우도 있기 때문에, isAppearing 상태를 저장해 오버레이가 다시 추가되는 것을 방지한다. | ||
} | ||
|
||
private func updateOverlay() { | ||
FullScreenOverlayContainer.shared.updateOverlay(overlay, for: id, in: presentationSpace) | ||
} | ||
|
||
private func removeOverlay() { | ||
FullScreenOverlayContainer.shared.removeOverlay(for: id, in: presentationSpace) | ||
} | ||
} | ||
|
||
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) | ||
private extension View { | ||
|
||
func onUpdate(perform action: (() -> Void)? = nil) -> some View { | ||
if let action = action { | ||
DispatchQueue.main.async(execute: action) | ||
} | ||
return self | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import SwiftUI | ||
|
||
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) | ||
public enum PresentationSpace: Equatable, Hashable { | ||
case named(AnyHashable) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import SwiftUI | ||
|
||
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) | ||
public extension View { | ||
|
||
func fullScreenOverlayPresentationSpace<T: Hashable>(name: T) -> some View { | ||
self | ||
.modifier(FullScreenOverlayPresenter(presentationSpace: .named(name))) | ||
} | ||
|
||
@ViewBuilder func fullScreenOverlay<Overlay: View>( | ||
presentationSpace: PresentationSpace, | ||
@ViewBuilder content: () -> Overlay | ||
) -> some View { | ||
self.modifier(FullScreenOverlaySetter(overlay: content(), presentationSpace: presentationSpace)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import SwiftUI | ||
import FullScreenOverlay | ||
|
||
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) | ||
private struct RootView: View { | ||
|
||
@State private var isPresentingBottomSheet: Bool = false | ||
|
||
var body: some View { | ||
List { | ||
Button( | ||
"Present Bottom Sheet", | ||
action: { isPresentingBottomSheet = true } | ||
) | ||
.fullScreenOverlay(presentationSpace: .named("RootView")) { | ||
if isPresentingBottomSheet { | ||
BottomSheet(onDismiss: { isPresentingBottomSheet = false }) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) | ||
private struct BottomSheet: View { | ||
|
||
var onDismiss: () -> Void | ||
|
||
@State private var isAppearing: Bool = false | ||
|
||
var body: some View { | ||
Color.black.opacity(0.2) | ||
.edgesIgnoringSafeArea(.all) | ||
.zIndex(-1) | ||
.onTapGesture(perform: onDismiss) | ||
.transition(.opacity.animation(.default)) | ||
VStack { | ||
Text("Bottom Sheet") | ||
.font(.title.weight(.semibold)) | ||
.padding(.vertical, 128) | ||
Button("Dismiss", action: { isAppearing = false; onDismiss() }) | ||
} | ||
.padding(.vertical, 32) | ||
.frame(maxWidth: .infinity) | ||
.background( | ||
Color.white | ||
.shadow(radius: 1) | ||
.edgesIgnoringSafeArea(.all) | ||
) | ||
.frame(maxHeight: .infinity, alignment: .bottom) | ||
.transition(.move(edge: .bottom)) | ||
.animation(.spring()) | ||
} | ||
} | ||
|
||
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) | ||
internal struct SwiftUIView_Previews: PreviewProvider { | ||
|
||
static var previews: some View { | ||
RootView() | ||
.fullScreenOverlayPresentationSpace(name: "RootView") | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.