FixedSizeModifier.swift 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. extension View {
  2. /// Locks this view's size on both the horizontal and vertical axes.
  3. public func fixedSize() -> some View {
  4. FixedSizeModifier(self, horizontal: true, vertical: true)
  5. }
  6. /// Locks this view's size on the specified axes.
  7. ///
  8. /// What this modifier does is propose an unspecified size along the specified
  9. /// dimensions; this has the effect of making the view immune to changes in
  10. /// size proposals along its 'fixed' axes. But the view's size along those
  11. /// axes **may still change** if the incoming size proposal changes along a
  12. /// 'non-fixed' axis. This is particularly pertinent in the case of views like
  13. /// ``Text``, which have a tradeoff between width and height; a 'fixed'
  14. /// horizontal size can still change if the vertical size changes, and vice
  15. /// versa.
  16. ///
  17. /// If both `horizontal` and `vertical` are `true` (i.e. if both axes are
  18. /// 'fixed'), then the child will take on its ideal size along both axes and
  19. /// will _actually_ be of a fixed size. ``fixedSize()`` (with no arguments)
  20. /// provides a shorthand for this.
  21. ///
  22. /// - Parameters:
  23. /// - horizontal: Whether to lock this view's size on the horizontal axis.
  24. /// - vertical: Whether to lock this view's size on the vertical axis.
  25. public func fixedSize(horizontal: Bool, vertical: Bool) -> some View {
  26. FixedSizeModifier(self, horizontal: horizontal, vertical: vertical)
  27. }
  28. }
  29. struct FixedSizeModifier<Child: View>: TypeSafeView {
  30. var body: TupleView1<Child>
  31. var horizontal: Bool
  32. var vertical: Bool
  33. init(_ child: Child, horizontal: Bool, vertical: Bool) {
  34. body = TupleView1(child)
  35. self.horizontal = horizontal
  36. self.vertical = vertical
  37. }
  38. func children<Backend: BaseAppBackend>(
  39. backend: Backend,
  40. snapshots: [ViewGraphSnapshotter.NodeSnapshot]?,
  41. environment: EnvironmentValues
  42. ) -> TupleViewChildren1<Child> {
  43. body.children(backend: backend, snapshots: snapshots, environment: environment)
  44. }
  45. func asWidget<Backend: BaseAppBackend>(
  46. _ children: TupleViewChildren1<Child>,
  47. backend: Backend
  48. ) -> Backend.Widget {
  49. let container = backend.createContainer()
  50. backend.insert(children.child0.widget.into(), into: container, at: 0)
  51. return container
  52. }
  53. func computeLayout<Backend: BaseAppBackend>(
  54. _ widget: Backend.Widget,
  55. children: TupleViewChildren1<Child>,
  56. proposedSize: ProposedViewSize,
  57. environment: EnvironmentValues,
  58. backend: Backend
  59. ) -> ViewLayoutResult {
  60. var childProposal = proposedSize
  61. if horizontal {
  62. childProposal.width = nil
  63. }
  64. if vertical {
  65. childProposal.height = nil
  66. }
  67. let childResult = children.child0.computeLayout(
  68. with: body.view0,
  69. proposedSize: childProposal,
  70. environment: environment
  71. )
  72. return ViewLayoutResult(
  73. size: childResult.size,
  74. childResults: [childResult]
  75. )
  76. }
  77. func commit<Backend: BaseAppBackend>(
  78. _ widget: Backend.Widget,
  79. children: TupleViewChildren1<Child>,
  80. layout: ViewLayoutResult,
  81. environment: EnvironmentValues,
  82. backend: Backend
  83. ) {
  84. let childResult = children.child0.commit()
  85. let childPosition = Alignment.center.position(
  86. ofChild: childResult.size.vector,
  87. in: layout.size.vector
  88. )
  89. backend.setPosition(ofChildAt: 0, in: widget, to: childPosition)
  90. backend.setSize(of: widget, to: layout.size.vector)
  91. }
  92. }