OverlayModifier.swift 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. extension View {
  2. /// Overlays another view on top of this view.
  3. ///
  4. /// - Parameter alignment: The alignment that the modifier uses to position
  5. /// the overlay relative to the underlying content.
  6. /// - Parameter content: The view to overlay this view with.
  7. public func overlay(
  8. alignment: Alignment = .center,
  9. @ViewBuilder content: () -> some View
  10. ) -> some View {
  11. OverlayModifier(content: self, overlay: content(), alignment: alignment)
  12. }
  13. }
  14. struct OverlayModifier<Content: View, Overlay: View>: TypeSafeView {
  15. typealias Children = TupleView2<Content, Overlay>.Children
  16. var body: TupleView2<Content, Overlay>
  17. var alignment: Alignment
  18. init(content: Content, overlay: Overlay, alignment: Alignment) {
  19. body = TupleView2(content, overlay)
  20. self.alignment = alignment
  21. }
  22. func children<Backend: BaseAppBackend>(
  23. backend: Backend,
  24. snapshots: [ViewGraphSnapshotter.NodeSnapshot]?,
  25. environment: EnvironmentValues
  26. ) -> TupleView2<Content, Overlay>.Children {
  27. body.children(
  28. backend: backend,
  29. snapshots: snapshots,
  30. environment: environment
  31. )
  32. }
  33. func layoutableChildren<Backend: BaseAppBackend>(
  34. backend: Backend,
  35. children: TupleView2<Content, Overlay>.Children
  36. ) -> [LayoutSystem.LayoutableChild] {
  37. []
  38. }
  39. func asWidget<Backend: BaseAppBackend>(
  40. _ children: TupleView2<Content, Overlay>.Children,
  41. backend: Backend
  42. ) -> Backend.Widget {
  43. body.asWidget(children, backend: backend)
  44. }
  45. func computeLayout<Backend: BaseAppBackend>(
  46. _ widget: Backend.Widget,
  47. children: TupleView2<Content, Overlay>.Children,
  48. proposedSize: ProposedViewSize,
  49. environment: EnvironmentValues,
  50. backend: Backend
  51. ) -> ViewLayoutResult {
  52. let contentResult = children.child0.computeLayout(
  53. with: body.view0,
  54. proposedSize: proposedSize,
  55. environment: environment
  56. )
  57. let contentSize = contentResult.size
  58. let overlayResult = children.child1.computeLayout(
  59. with: body.view1,
  60. proposedSize: ProposedViewSize(contentSize),
  61. environment: environment
  62. )
  63. let overlaySize = overlayResult.size
  64. let size = ViewSize(
  65. max(contentSize.width, overlaySize.width),
  66. max(contentSize.height, overlaySize.height)
  67. )
  68. return ViewLayoutResult(
  69. size: size,
  70. childResults: [contentResult, overlayResult]
  71. )
  72. }
  73. func commit<Backend: BaseAppBackend>(
  74. _ widget: Backend.Widget,
  75. children: TupleView2<Content, Overlay>.Children,
  76. layout: ViewLayoutResult,
  77. environment: EnvironmentValues,
  78. backend: Backend
  79. ) {
  80. let frameSize = layout.size.vector
  81. let contentSize = children.child0.commit().size.vector
  82. let overlaySize = children.child1.commit().size.vector
  83. let contentPosition = alignment.position(ofChild: contentSize, in: frameSize)
  84. let overlayPosition = alignment.position(ofChild: overlaySize, in: frameSize)
  85. backend.setPosition(ofChildAt: 0, in: widget, to: contentPosition)
  86. backend.setPosition(ofChildAt: 1, in: widget, to: overlayPosition)
  87. backend.setSize(of: widget, to: frameSize)
  88. }
  89. }