_BuiltinPickerImplementation.swift 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /// The underlying view used to render the various ``_BuiltinPickerStyle``s.
  2. public struct _BuiltinPickerImplementation: TypeSafeView {
  3. public var body: EmptyView { return EmptyView() }
  4. var style: BackendPickerStyle
  5. var options: [String]
  6. var selectedIndex: Binding<Int?>
  7. func children<Backend: BaseAppBackend>(
  8. backend: Backend,
  9. snapshots: [ViewGraphSnapshotter.NodeSnapshot]?,
  10. environment: EnvironmentValues
  11. ) -> BuiltinPickerChildren {
  12. BuiltinPickerChildren(
  13. container: AnyWidget(backend.createContainer()),
  14. picker: nil,
  15. style: style
  16. )
  17. }
  18. func asWidget<Backend: BaseAppBackend>(
  19. _ children: BuiltinPickerChildren,
  20. backend: Backend
  21. ) -> Backend.Widget {
  22. children.container.widget as! Backend.Widget
  23. }
  24. func computeLayout<Backend: BaseAppBackend>(
  25. _ widget: Backend.Widget,
  26. children: BuiltinPickerChildren,
  27. proposedSize: ProposedViewSize,
  28. environment: EnvironmentValues,
  29. backend: Backend
  30. ) -> ViewLayoutResult {
  31. var pickerWidget: Backend.Widget
  32. if let picker = children.picker, children.style == self.style {
  33. pickerWidget = picker.widget as! Backend.Widget
  34. } else {
  35. let containerWidget = children.container.widget as! Backend.Widget
  36. backend.removeAllChildren(of: containerWidget)
  37. pickerWidget = backend.createPicker(style: style)
  38. children.style = self.style
  39. children.picker = AnyWidget(pickerWidget)
  40. backend.insert(pickerWidget, into: containerWidget, at: 0)
  41. backend.setPosition(ofChildAt: 0, in: containerWidget, to: .zero)
  42. }
  43. // TODO: Implement picker sizing within SwiftCrossUI so that we can
  44. // properly separate committing logic out into `commit`.
  45. backend.updatePicker(
  46. pickerWidget,
  47. options: options,
  48. environment: environment
  49. ) {
  50. selectedIndex.wrappedValue = $0
  51. }
  52. backend.setSelectedOption(ofPicker: pickerWidget, to: selectedIndex.wrappedValue)
  53. // Special handling for UIKitBackend:
  54. // When backed by a UITableView, its natural size is -1 x -1,
  55. // but it can and should be as large as reasonable
  56. let naturalSize = backend.naturalSize(of: pickerWidget)
  57. let size: ViewSize
  58. if naturalSize == SIMD2(-1, -1) {
  59. size = proposedSize.replacingUnspecifiedDimensions(by: ViewSize(10, 10))
  60. } else {
  61. size = ViewSize(naturalSize)
  62. }
  63. return ViewLayoutResult.leafView(size: size)
  64. }
  65. func commit<Backend: BaseAppBackend>(
  66. _ widget: Backend.Widget,
  67. children: BuiltinPickerChildren,
  68. layout: ViewLayoutResult,
  69. environment: EnvironmentValues,
  70. backend: Backend
  71. ) {
  72. backend.setSize(of: widget, to: layout.size.vector)
  73. backend.setSize(
  74. of: children.picker!.widget as! Backend.Widget,
  75. to: layout.size.vector
  76. )
  77. }
  78. }
  79. /// The children of a built-in picker. Pickers don't actually have child nodes,
  80. /// we just use this to persist information between updates.
  81. final class BuiltinPickerChildren: ViewGraphNodeChildren {
  82. var container: AnyWidget
  83. var picker: AnyWidget?
  84. var style: BackendPickerStyle
  85. init(container: AnyWidget, picker: AnyWidget? = nil, style: BackendPickerStyle) {
  86. self.container = container
  87. self.picker = picker
  88. self.style = style
  89. }
  90. var widgets: [AnyWidget] { [container] }
  91. var erasedNodes: [ErasedViewGraphNode] { [] }
  92. }