RCTSurfaceHostingComponent.mm 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import "RCTSurfaceHostingComponent.h"
  8. #import "RCTSurfaceHostingComponent+Internal.h"
  9. #import <UIKit/UIKit.h>
  10. #import <ComponentKit/CKComponentSubclass.h>
  11. #import <React/RCTSurface.h>
  12. #import <React/RCTSurfaceView.h>
  13. #import "RCTSurfaceHostingComponentController.h"
  14. #import "RCTSurfaceHostingComponentState.h"
  15. @implementation RCTSurfaceHostingComponent
  16. + (Class<CKComponentControllerProtocol>)controllerClass
  17. {
  18. return [RCTSurfaceHostingComponentController class];
  19. }
  20. + (id)initialState
  21. {
  22. return [RCTSurfaceHostingComponentState new];
  23. }
  24. + (instancetype)newWithSurface:(RCTSurface *)surface options:(RCTSurfaceHostingComponentOptions)options
  25. {
  26. CKComponentScope scope(self, surface);
  27. RCTSurfaceHostingComponentState *const state = scope.state();
  28. RCTSurfaceHostingComponentState *const newState =
  29. [RCTSurfaceHostingComponentState newWithStage:surface.stage
  30. intrinsicSize:surface.intrinsicSize];
  31. if (![state isEqual:newState]) {
  32. CKComponentScope::replaceState(scope, newState);
  33. }
  34. RCTSurfaceHostingComponent *const component =
  35. [super newWithView:{[UIView class]} size:{}];
  36. if (component) {
  37. component->_state = scope.state();
  38. component->_surface = surface;
  39. component->_options = options;
  40. }
  41. return component;
  42. }
  43. - (CKComponentLayout)computeLayoutThatFits:(CKSizeRange)constrainedSize
  44. {
  45. // Optimistically communicating layout constraints to the `_surface`,
  46. // just to provide layout constraints to React Native as early as possible.
  47. // React Native *may* use this info later during applying the own state and
  48. // related laying out in parallel with ComponentKit execution.
  49. // This call will not interfere (or introduce any negative side effects) with
  50. // following invocation of `sizeThatFitsMinimumSize:maximumSize:`.
  51. // A weak point: We assume here that this particular layout will be
  52. // mounted eventually, which is technically not guaranteed by ComponentKit.
  53. // Therefore we also assume that the last layout calculated in a sequence
  54. // will be mounted anyways, which is probably true for all *real* use cases.
  55. // We plan to tackle this problem during the next big step in improving
  56. // interop compatibilities of React Native which will enable us granularly
  57. // control React Native mounting blocks and, as a result, implement
  58. // truly synchronous mounting stage between React Native and ComponentKit.
  59. [_surface setMinimumSize:constrainedSize.min
  60. maximumSize:constrainedSize.max];
  61. // Just in case of the very first building pass, we give React Native a chance
  62. // to prepare its internals for coming synchronous measuring.
  63. [_surface synchronouslyWaitForStage:RCTSurfaceStageSurfaceDidInitialLayout
  64. timeout:_options.synchronousLayoutingTimeout];
  65. CGSize fittingSize = CGSizeZero;
  66. if (_surface.stage & RCTSurfaceStageSurfaceDidInitialLayout) {
  67. fittingSize = [_surface sizeThatFitsMinimumSize:constrainedSize.min
  68. maximumSize:constrainedSize.max];
  69. }
  70. else {
  71. fittingSize = _options.activityIndicatorSize;
  72. }
  73. fittingSize = constrainedSize.clamp(fittingSize);
  74. return {self, fittingSize};
  75. }
  76. - (CKComponentBoundsAnimation)boundsAnimationFromPreviousComponent:(RCTSurfaceHostingComponent *)previousComponent
  77. {
  78. if (_options.boundsAnimations && (previousComponent->_state.stage != _state.stage)) {
  79. return {
  80. .mode = CKComponentBoundsAnimationModeDefault,
  81. .duration = 0.25,
  82. .options = UIViewAnimationOptionCurveEaseInOut,
  83. };
  84. }
  85. return {};
  86. }
  87. @end