OnDisappearModifier.swift 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. extension View {
  2. /// Adds an action to be performed after this view disappears.
  3. ///
  4. /// `onDisappear` actions on outermost views are called first and propagate
  5. /// down to the leaf views due to essentially relying on the `deinit` of the
  6. /// modifier view's ``ViewGraphNode``.
  7. ///
  8. /// - Parameter action: The action to perform when this view disappears.
  9. public func onDisappear(perform action: @escaping @Sendable @MainActor () -> Void) -> some View
  10. {
  11. OnDisappearModifier(body: TupleView1(self), action: action)
  12. }
  13. }
  14. struct OnDisappearModifier<Content: View>: TypeSafeView {
  15. var body: TupleView1<Content>
  16. var action: @Sendable @MainActor () -> Void
  17. func children<Backend: BaseAppBackend>(
  18. backend: Backend,
  19. snapshots: [ViewGraphSnapshotter.NodeSnapshot]?,
  20. environment: EnvironmentValues
  21. ) -> OnDisappearModifierChildren {
  22. OnDisappearModifierChildren(
  23. wrappedChildren: defaultChildren(
  24. backend: backend,
  25. snapshots: snapshots,
  26. environment: environment
  27. ),
  28. action: action
  29. )
  30. }
  31. func layoutableChildren<Backend: BaseAppBackend>(
  32. backend: Backend,
  33. children: OnDisappearModifierChildren
  34. ) -> [LayoutSystem.LayoutableChild] {
  35. defaultLayoutableChildren(
  36. backend: backend,
  37. children: children.wrappedChildren
  38. )
  39. }
  40. func asWidget<Backend: BaseAppBackend>(
  41. _ children: OnDisappearModifierChildren,
  42. backend: Backend
  43. ) -> Backend.Widget {
  44. defaultAsWidget(children.wrappedChildren, backend: backend)
  45. }
  46. func computeLayout<Backend: BaseAppBackend>(
  47. _ widget: Backend.Widget,
  48. children: OnDisappearModifierChildren,
  49. proposedSize: ProposedViewSize,
  50. environment: EnvironmentValues,
  51. backend: Backend
  52. ) -> ViewLayoutResult {
  53. defaultComputeLayout(
  54. widget,
  55. children: children.wrappedChildren,
  56. proposedSize: proposedSize,
  57. environment: environment,
  58. backend: backend
  59. )
  60. }
  61. func commit<Backend: BaseAppBackend>(
  62. _ widget: Backend.Widget,
  63. children: OnDisappearModifierChildren,
  64. layout: ViewLayoutResult,
  65. environment: EnvironmentValues,
  66. backend: Backend
  67. ) {
  68. defaultCommit(
  69. widget,
  70. children: children.wrappedChildren,
  71. layout: layout,
  72. environment: environment,
  73. backend: backend
  74. )
  75. }
  76. }
  77. class OnDisappearModifierChildren: ViewGraphNodeChildren {
  78. var wrappedChildren: any ViewGraphNodeChildren
  79. var action: @Sendable @MainActor () -> Void
  80. var widgets: [AnyWidget] {
  81. wrappedChildren.widgets
  82. }
  83. var erasedNodes: [ErasedViewGraphNode] {
  84. wrappedChildren.erasedNodes
  85. }
  86. init(
  87. wrappedChildren: any ViewGraphNodeChildren,
  88. action: @escaping @Sendable @MainActor () -> Void
  89. ) {
  90. self.wrappedChildren = wrappedChildren
  91. self.action = action
  92. }
  93. deinit {
  94. Task { @MainActor [action] in
  95. action()
  96. }
  97. }
  98. }