Skip to content

Instantly share code, notes, and snippets.

@WinterArch
Last active November 14, 2023 08:05
Show Gist options
  • Select an option

  • Save WinterArch/c34e2351de0bc82e44eefdf608dbb5a6 to your computer and use it in GitHub Desktop.

Select an option

Save WinterArch/c34e2351de0bc82e44eefdf608dbb5a6 to your computer and use it in GitHub Desktop.
FullScreenPop_SwiftUI
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