react-native-navigation的迁移库

RCCNavigationController.m 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. #import "RCCNavigationController.h"
  2. #import "RCCViewController.h"
  3. #import "RCCManager.h"
  4. #import <React/RCTEventDispatcher.h>
  5. #import <React/RCTConvert.h>
  6. #import <objc/runtime.h>
  7. #import "RCCTitleViewHelper.h"
  8. #import "UIViewController+Rotation.h"
  9. @implementation RCCNavigationController
  10. NSString const *CALLBACK_ASSOCIATED_KEY = @"RCCNavigationController.CALLBACK_ASSOCIATED_KEY";
  11. NSString const *CALLBACK_ASSOCIATED_ID = @"RCCNavigationController.CALLBACK_ASSOCIATED_ID";
  12. -(UIInterfaceOrientationMask)supportedInterfaceOrientations {
  13. return [self supportedControllerOrientations];
  14. }
  15. - (instancetype)initWithProps:(NSDictionary *)props children:(NSArray *)children globalProps:(NSDictionary*)globalProps bridge:(RCTBridge *)bridge
  16. {
  17. NSString *component = props[@"component"];
  18. if (!component) return nil;
  19. NSDictionary *passProps = props[@"passProps"];
  20. NSDictionary *navigatorStyle = props[@"style"];
  21. RCCViewController *viewController = [[RCCViewController alloc] initWithComponent:component passProps:passProps navigatorStyle:navigatorStyle globalProps:globalProps bridge:bridge];
  22. if (!viewController) return nil;
  23. NSArray *leftButtons = props[@"leftButtons"];
  24. if (leftButtons)
  25. {
  26. [self setButtons:leftButtons viewController:viewController side:@"left" animated:NO];
  27. }
  28. NSArray *rightButtons = props[@"rightButtons"];
  29. if (rightButtons)
  30. {
  31. [self setButtons:rightButtons viewController:viewController side:@"right" animated:NO];
  32. }
  33. self = [super initWithRootViewController:viewController];
  34. if (!self) return nil;
  35. self.delegate = self;
  36. self.navigationBar.translucent = NO; // default
  37. [self processTitleView:viewController
  38. props:props
  39. style:navigatorStyle];
  40. [self setRotation:props];
  41. return self;
  42. }
  43. - (void)performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams bridge:(RCTBridge *)bridge
  44. {
  45. BOOL animated = actionParams[@"animated"] ? [actionParams[@"animated"] boolValue] : YES;
  46. // push
  47. if ([performAction isEqualToString:@"push"])
  48. {
  49. NSString *component = actionParams[@"component"];
  50. if (!component) return;
  51. NSDictionary *passProps = actionParams[@"passProps"];
  52. NSDictionary *navigatorStyle = actionParams[@"style"];
  53. // merge the navigatorStyle of our parent
  54. if ([self.topViewController isKindOfClass:[RCCViewController class]])
  55. {
  56. RCCViewController *parent = (RCCViewController*)self.topViewController;
  57. NSMutableDictionary *mergedStyle = [NSMutableDictionary dictionaryWithDictionary:parent.navigatorStyle];
  58. // there are a few styles that we don't want to remember from our parent (they should be local)
  59. [mergedStyle removeObjectForKey:@"navBarHidden"];
  60. [mergedStyle removeObjectForKey:@"statusBarHidden"];
  61. [mergedStyle removeObjectForKey:@"navBarHideOnScroll"];
  62. [mergedStyle removeObjectForKey:@"drawUnderNavBar"];
  63. [mergedStyle removeObjectForKey:@"drawUnderTabBar"];
  64. [mergedStyle removeObjectForKey:@"statusBarBlur"];
  65. [mergedStyle removeObjectForKey:@"navBarBlur"];
  66. [mergedStyle removeObjectForKey:@"navBarTranslucent"];
  67. [mergedStyle removeObjectForKey:@"statusBarHideWithNavBar"];
  68. [mergedStyle removeObjectForKey:@"autoAdjustScrollViewInsets"];
  69. [mergedStyle removeObjectForKey:@"statusBarTextColorSchemeSingleScreen"];
  70. [mergedStyle removeObjectForKey:@"disabledBackGesture"];
  71. [mergedStyle addEntriesFromDictionary:navigatorStyle];
  72. navigatorStyle = mergedStyle;
  73. }
  74. RCCViewController *viewController = [[RCCViewController alloc] initWithComponent:component passProps:passProps navigatorStyle:navigatorStyle globalProps:nil bridge:bridge];
  75. [self processTitleView:viewController
  76. props:actionParams
  77. style:navigatorStyle];
  78. NSString *backButtonTitle = actionParams[@"backButtonTitle"];
  79. if (backButtonTitle)
  80. {
  81. UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:backButtonTitle
  82. style:UIBarButtonItemStylePlain
  83. target:nil
  84. action:nil];
  85. self.topViewController.navigationItem.backBarButtonItem = backItem;
  86. }
  87. else
  88. {
  89. self.topViewController.navigationItem.backBarButtonItem = nil;
  90. }
  91. NSNumber *backButtonHidden = actionParams[@"backButtonHidden"];
  92. BOOL backButtonHiddenBool = backButtonHidden ? [backButtonHidden boolValue] : NO;
  93. if (backButtonHiddenBool)
  94. {
  95. viewController.navigationItem.hidesBackButton = YES;
  96. }
  97. NSArray *leftButtons = actionParams[@"leftButtons"];
  98. if (leftButtons)
  99. {
  100. [self setButtons:leftButtons viewController:viewController side:@"left" animated:NO];
  101. }
  102. NSArray *rightButtons = actionParams[@"rightButtons"];
  103. if (rightButtons)
  104. {
  105. [self setButtons:rightButtons viewController:viewController side:@"right" animated:NO];
  106. }
  107. [self pushViewController:viewController animated:animated];
  108. return;
  109. }
  110. // pop
  111. if ([performAction isEqualToString:@"pop"])
  112. {
  113. [self popViewControllerAnimated:animated];
  114. return;
  115. }
  116. // popToRoot
  117. if ([performAction isEqualToString:@"popToRoot"])
  118. {
  119. [self popToRootViewControllerAnimated:animated];
  120. return;
  121. }
  122. // resetTo
  123. if ([performAction isEqualToString:@"resetTo"])
  124. {
  125. NSString *component = actionParams[@"component"];
  126. if (!component) return;
  127. NSDictionary *passProps = actionParams[@"passProps"];
  128. NSDictionary *navigatorStyle = actionParams[@"style"];
  129. RCCViewController *viewController = [[RCCViewController alloc] initWithComponent:component passProps:passProps navigatorStyle:navigatorStyle globalProps:nil bridge:bridge];
  130. [self processTitleView:viewController
  131. props:actionParams
  132. style:navigatorStyle];
  133. NSArray *leftButtons = actionParams[@"leftButtons"];
  134. if (leftButtons)
  135. {
  136. [self setButtons:leftButtons viewController:viewController side:@"left" animated:NO];
  137. }
  138. NSArray *rightButtons = actionParams[@"rightButtons"];
  139. if (rightButtons)
  140. {
  141. [self setButtons:rightButtons viewController:viewController side:@"right" animated:NO];
  142. }
  143. BOOL animated = actionParams[@"animated"] ? [actionParams[@"animated"] boolValue] : YES;
  144. [self setViewControllers:@[viewController] animated:animated];
  145. return;
  146. }
  147. // setButtons
  148. if ([performAction isEqualToString:@"setButtons"])
  149. {
  150. NSArray *buttons = actionParams[@"buttons"];
  151. BOOL animated = actionParams[@"animated"] ? [actionParams[@"animated"] boolValue] : YES;
  152. NSString *side = actionParams[@"side"] ? actionParams[@"side"] : @"left";
  153. [self setButtons:buttons viewController:self.topViewController side:side animated:animated];
  154. return;
  155. }
  156. // setTitle
  157. if ([performAction isEqualToString:@"setTitle"] || [performAction isEqualToString:@"setTitleImage"])
  158. {
  159. NSDictionary *navigatorStyle = actionParams[@"style"];
  160. [self processTitleView:self.topViewController
  161. props:actionParams
  162. style:navigatorStyle];
  163. return;
  164. }
  165. // toggleNavBar
  166. if ([performAction isEqualToString:@"setHidden"]) {
  167. NSNumber *animated = actionParams[@"animated"];
  168. BOOL animatedBool = animated ? [animated boolValue] : YES;
  169. NSNumber *setHidden = actionParams[@"hidden"];
  170. BOOL isHiddenBool = setHidden ? [setHidden boolValue] : NO;
  171. RCCViewController *topViewController = ((RCCViewController*)self.topViewController);
  172. topViewController.navigatorStyle[@"navBarHidden"] = setHidden;
  173. [topViewController setNavBarVisibilityChange:animatedBool];
  174. }
  175. // setStyle
  176. if ([performAction isEqualToString:@"setStyle"])
  177. {
  178. NSDictionary *navigatorStyle = actionParams;
  179. // merge the navigatorStyle of our parent
  180. if ([self.topViewController isKindOfClass:[RCCViewController class]])
  181. {
  182. RCCViewController *parent = (RCCViewController*)self.topViewController;
  183. NSMutableDictionary *mergedStyle = [NSMutableDictionary dictionaryWithDictionary:parent.navigatorStyle];
  184. // there are a few styles that we don't want to remember from our parent (they should be local)
  185. [mergedStyle setValuesForKeysWithDictionary:navigatorStyle];
  186. navigatorStyle = mergedStyle;
  187. parent.navigatorStyle = navigatorStyle;
  188. [parent setStyleOnInit];
  189. [parent updateStyle];
  190. }
  191. }
  192. }
  193. -(void)onButtonPress:(UIBarButtonItem*)barButtonItem
  194. {
  195. NSString *callbackId = objc_getAssociatedObject(barButtonItem, &CALLBACK_ASSOCIATED_KEY);
  196. if (!callbackId) return;
  197. NSString *buttonId = objc_getAssociatedObject(barButtonItem, &CALLBACK_ASSOCIATED_ID);
  198. [[[RCCManager sharedInstance] getBridge].eventDispatcher sendAppEventWithName:callbackId body:@
  199. {
  200. @"type": @"NavBarButtonPress",
  201. @"id": buttonId ? buttonId : [NSNull null]
  202. }];
  203. }
  204. -(void)setButtons:(NSArray*)buttons viewController:(UIViewController*)viewController side:(NSString*)side animated:(BOOL)animated
  205. {
  206. NSMutableArray *barButtonItems = [NSMutableArray new];
  207. for (NSDictionary *button in buttons)
  208. {
  209. NSString *title = button[@"title"];
  210. UIImage *iconImage = nil;
  211. id icon = button[@"icon"];
  212. if (icon) iconImage = [RCTConvert UIImage:icon];
  213. UIBarButtonItem *barButtonItem;
  214. if (iconImage)
  215. {
  216. barButtonItem = [[UIBarButtonItem alloc] initWithImage:iconImage style:UIBarButtonItemStylePlain target:self action:@selector(onButtonPress:)];
  217. }
  218. else if (title)
  219. {
  220. barButtonItem = [[UIBarButtonItem alloc] initWithTitle:title style:UIBarButtonItemStylePlain target:self action:@selector(onButtonPress:)];
  221. }
  222. else continue;
  223. objc_setAssociatedObject(barButtonItem, &CALLBACK_ASSOCIATED_KEY, button[@"onPress"], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  224. [barButtonItems addObject:barButtonItem];
  225. NSString *buttonId = button[@"id"];
  226. if (buttonId)
  227. {
  228. objc_setAssociatedObject(barButtonItem, &CALLBACK_ASSOCIATED_ID, buttonId, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  229. }
  230. NSNumber *disabled = button[@"disabled"];
  231. BOOL disabledBool = disabled ? [disabled boolValue] : NO;
  232. if (disabledBool) {
  233. [barButtonItem setEnabled:NO];
  234. }
  235. NSNumber *disableIconTintString = button[@"disableIconTint"];
  236. BOOL disableIconTint = disableIconTintString ? [disableIconTintString boolValue] : NO;
  237. if (disableIconTint) {
  238. [barButtonItem setImage:[barButtonItem.image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
  239. }
  240. NSString *testID = button[@"testID"];
  241. if (testID)
  242. {
  243. barButtonItem.accessibilityIdentifier = testID;
  244. }
  245. }
  246. if ([side isEqualToString:@"left"])
  247. {
  248. [viewController.navigationItem setLeftBarButtonItems:barButtonItems animated:animated];
  249. }
  250. if ([side isEqualToString:@"right"])
  251. {
  252. [viewController.navigationItem setRightBarButtonItems:barButtonItems animated:animated];
  253. }
  254. }
  255. -(void)processTitleView:(UIViewController*)viewController
  256. props:(NSDictionary*)props
  257. style:(NSDictionary*)style
  258. {
  259. RCCTitleViewHelper *titleViewHelper = [[RCCTitleViewHelper alloc] init:viewController
  260. navigationController:self
  261. title:props[@"title"]
  262. subtitle:props[@"subtitle"]
  263. titleImageData:props[@"titleImage"]];
  264. [titleViewHelper setup:style];
  265. }
  266. - (UIStatusBarStyle)preferredStatusBarStyle {
  267. return [self.topViewController preferredStatusBarStyle];
  268. }
  269. #pragma mark - UINavigationControllerDelegate
  270. -(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
  271. [viewController setNeedsStatusBarAppearanceUpdate];
  272. }
  273. @end