Last active
November 14, 2023 08:05
-
-
Save WinterArch/c34e2351de0bc82e44eefdf608dbb5a6 to your computer and use it in GitHub Desktop.
FullScreenPop_SwiftUI
This file contains hidden or 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
| import SwiftUI | |
| // Source from Kavsoft-youtube | |
| // https://www.youtube.com/watch?v=4ceKPSTlL4I | |
| struct FullSwipeNavigationStack<Content: View>: View { | |
| @ViewBuilder var content: Content | |
| /// Full Swipe Custom Gesture | |
| @State private var customGesture: UIPanGestureRecognizer = { | |
| let gesture = UIPanGestureRecognizer() | |
| gesture.name = UUID().uuidString | |
| gesture.isEnabled = false | |
| return gesture | |
| }() | |
| var body: some View { | |
| NavigationStack { | |
| content | |
| .background { | |
| AttachGestureView(gesture: $customGesture) | |
| } | |
| } | |
| .environment(\.popGestureID, customGesture.name) | |
| .onReceive(NotificationCenter.default.publisher(for: .init(customGesture.name ?? "")), perform: { info in | |
| if let userInfo = info.userInfo, | |
| let status = userInfo["status"] as? Bool { | |
| customGesture.isEnabled = status | |
| } | |
| }) | |
| } | |
| } | |
| fileprivate struct AttachGestureView: UIViewRepresentable { | |
| @Binding var gesture: UIPanGestureRecognizer | |
| func makeUIView(context: Context) -> some UIView { | |
| return UIView() | |
| } | |
| func updateUIView(_ uiView: UIViewType, context: Context) { | |
| DispatchQueue.main.asyncAfter(deadline: .now()+0.02) { | |
| /// 找双亲控制器 | |
| if let parentVC = uiView.parentVC { | |
| if let navigationController = parentVC.navigationController { | |
| /// 检查 如果已将手势添加到控制器 | |
| if let _ = navigationController.view.gestureRecognizers?.first(where: {$0.name==gesture.name}) { | |
| print("Already Attached") | |
| } else { | |
| navigationController.addFullSwipeGesture(gesture) | |
| print("Attached") | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| fileprivate struct PopNotificationID: EnvironmentKey { | |
| static var defaultValue: String? | |
| } | |
| fileprivate extension EnvironmentValues { | |
| var popGestureID: String? { | |
| get { | |
| self[PopNotificationID.self] | |
| } | |
| set { | |
| self[PopNotificationID.self] = newValue | |
| } | |
| } | |
| } | |
| extension View { | |
| @ViewBuilder func enableFullSwipePop(_ isEnabled: Bool) -> some View { | |
| self | |
| .modifier(FullSwipeModifier(isEnabled: isEnabled)) | |
| } | |
| } | |
| fileprivate struct FullSwipeModifier: ViewModifier { | |
| var isEnabled: Bool | |
| @Environment(\.popGestureID) private var gestureID | |
| func body(content: Content) -> some View { | |
| content | |
| .onChange(of: isEnabled) { newValue in | |
| print(gestureID) | |
| guard let gestureID = gestureID else { return } | |
| NotificationCenter.default.post(name: .init(gestureID), object: nil, userInfo: ["status": newValue]) | |
| } | |
| } | |
| } | |
| fileprivate extension UINavigationController { | |
| func addFullSwipeGesture(_ gesture: UIPanGestureRecognizer) { | |
| guard let gestureSelector = interactivePopGestureRecognizer?.value(forKey: "targets") else { return } | |
| gesture.setValue(gestureSelector, forKey: "targets") | |
| view.addGestureRecognizer(gesture) | |
| } | |
| } | |
| fileprivate extension UIView { | |
| var parentVC: UIViewController? { | |
| sequence(first: self) { | |
| $0.next | |
| }.first(where: { $0 is UIViewController }) as? UIViewController | |
| } | |
| } | |
| struct FullScreenPop: View { | |
| @State private var isEnabled: Bool = false | |
| var body: some View { | |
| FullSwipeNavigationStack { | |
| List { | |
| Section("头部用例") { | |
| NavigationLink("Full Swipe View") { | |
| List { | |
| Toggle("Enable Full Swipe Pop", isOn: $isEnabled) | |
| .enableFullSwipePop(isEnabled) | |
| } | |
| .navigationTitle("Full Swipe View") | |
| } | |
| NavigationLink("Leading Swipe View") { | |
| } | |
| } | |
| } | |
| .navigationTitle("Full Swipe Pop") | |
| } | |
| } | |
| } | |
| #Preview { | |
| FullScreenPop() | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment