react-native-navigation的迁移库

ScreenStack.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. package com.reactnativenavigation.screens;
  2. import android.support.annotation.Nullable;
  3. import android.support.v7.app.AppCompatActivity;
  4. import android.util.Log;
  5. import android.view.View;
  6. import android.widget.RelativeLayout;
  7. import android.widget.RelativeLayout.LayoutParams;
  8. import com.facebook.react.bridge.Callback;
  9. import com.reactnativenavigation.NavigationApplication;
  10. import com.reactnativenavigation.params.ContextualMenuParams;
  11. import com.reactnativenavigation.params.FabParams;
  12. import com.reactnativenavigation.params.ScreenParams;
  13. import com.reactnativenavigation.params.StyleParams;
  14. import com.reactnativenavigation.params.TitleBarButtonParams;
  15. import com.reactnativenavigation.params.TitleBarLeftButtonParams;
  16. import com.reactnativenavigation.utils.KeyboardVisibilityDetector;
  17. import com.reactnativenavigation.utils.Task;
  18. import com.reactnativenavigation.views.LeftButtonOnClickListener;
  19. import java.util.List;
  20. import java.util.Stack;
  21. public class ScreenStack {
  22. private static final String TAG = "ScreenStack";
  23. public interface OnScreenPop {
  24. void onScreenPopAnimationEnd();
  25. }
  26. private final AppCompatActivity activity;
  27. private RelativeLayout parent;
  28. private LeftButtonOnClickListener leftButtonOnClickListener;
  29. private Stack<Screen> stack = new Stack<>();
  30. private final KeyboardVisibilityDetector keyboardVisibilityDetector;
  31. private boolean isStackVisible = false;
  32. private final String navigatorId;
  33. public String getNavigatorId() {
  34. return navigatorId;
  35. }
  36. public ScreenStack(AppCompatActivity activity,
  37. RelativeLayout parent,
  38. String navigatorId,
  39. LeftButtonOnClickListener leftButtonOnClickListener) {
  40. this.activity = activity;
  41. this.parent = parent;
  42. this.navigatorId = navigatorId;
  43. this.leftButtonOnClickListener = leftButtonOnClickListener;
  44. keyboardVisibilityDetector = new KeyboardVisibilityDetector(parent);
  45. }
  46. public void pushInitialScreenWithAnimation(final ScreenParams initialScreenParams, LayoutParams params) {
  47. isStackVisible = true;
  48. pushInitialScreen(initialScreenParams, params);
  49. final Screen screen = stack.peek();
  50. screen.setOnDisplayListener(new Screen.OnDisplayListener() {
  51. @Override
  52. public void onDisplay() {
  53. screen.show(initialScreenParams.animateScreenTransitions);
  54. screen.setStyle();
  55. }
  56. });
  57. }
  58. public void pushInitialScreen(ScreenParams initialScreenParams, LayoutParams params) {
  59. Screen initialScreen = ScreenFactory.create(activity, initialScreenParams, leftButtonOnClickListener);
  60. initialScreen.setVisibility(View.INVISIBLE);
  61. addScreen(initialScreen, params);
  62. }
  63. public void push(final ScreenParams params, LayoutParams layoutParams) {
  64. Screen nextScreen = ScreenFactory.create(activity, params, leftButtonOnClickListener);
  65. final Screen previousScreen = stack.peek();
  66. if (isStackVisible) {
  67. pushScreenToVisibleStack(layoutParams, nextScreen, previousScreen);
  68. } else {
  69. pushScreenToInvisibleStack(layoutParams, nextScreen, previousScreen);
  70. }
  71. }
  72. private void pushScreenToVisibleStack(LayoutParams layoutParams, final Screen nextScreen, final Screen previousScreen) {
  73. nextScreen.setVisibility(View.INVISIBLE);
  74. addScreen(nextScreen, layoutParams);
  75. nextScreen.setOnDisplayListener(new Screen.OnDisplayListener() {
  76. @Override
  77. public void onDisplay() {
  78. nextScreen.show(nextScreen.screenParams.animateScreenTransitions, new Runnable() {
  79. @Override
  80. public void run() {
  81. parent.removeView(previousScreen);
  82. }
  83. });
  84. }
  85. });
  86. }
  87. private void pushScreenToInvisibleStack(LayoutParams layoutParams, Screen nextScreen, Screen previousScreen) {
  88. nextScreen.setVisibility(View.INVISIBLE);
  89. addScreen(nextScreen, layoutParams);
  90. parent.removeView(previousScreen);
  91. }
  92. private void addScreen(Screen screen, LayoutParams layoutParams) {
  93. addScreenBeforeSnackbarAndFabLayout(screen, layoutParams);
  94. stack.push(screen);
  95. }
  96. private void addScreenBeforeSnackbarAndFabLayout(Screen screen, LayoutParams layoutParams) {
  97. parent.addView(screen, parent.getChildCount() - 1, layoutParams);
  98. }
  99. public void pop(boolean animated) {
  100. pop(animated, null);
  101. }
  102. public void pop(final boolean animated, @Nullable final OnScreenPop onScreenPop) {
  103. if (!canPop()) {
  104. return;
  105. }
  106. final Screen toRemove = stack.pop();
  107. final Screen previous = stack.peek();
  108. if (keyboardVisibilityDetector.isKeyboardVisible()) {
  109. keyboardVisibilityDetector.setKeyboardCloseListener(new Runnable() {
  110. @Override
  111. public void run() {
  112. keyboardVisibilityDetector.setKeyboardCloseListener(null);
  113. swapScreens(animated, toRemove, previous, onScreenPop);
  114. }
  115. });
  116. keyboardVisibilityDetector.closeKeyboard();
  117. } else {
  118. swapScreens(animated, toRemove, previous, onScreenPop);
  119. }
  120. }
  121. private void swapScreens(boolean animated, final Screen toRemove, Screen previous, OnScreenPop onScreenPop) {
  122. readdPrevious(previous);
  123. previous.setStyle();
  124. toRemove.hide(animated, new Runnable() {
  125. @Override
  126. public void run() {
  127. toRemove.unmountReactView();
  128. parent.removeView(toRemove);
  129. }
  130. });
  131. if (onScreenPop != null) {
  132. onScreenPop.onScreenPopAnimationEnd();
  133. }
  134. }
  135. public Screen peek() {
  136. return stack.peek();
  137. }
  138. private void readdPrevious(Screen previous) {
  139. previous.setVisibility(View.VISIBLE);
  140. parent.addView(previous, 0);
  141. }
  142. public void popToRoot(boolean animated) {
  143. while (canPop()) {
  144. pop(animated);
  145. }
  146. }
  147. public void destroy() {
  148. for (Screen screen : stack) {
  149. screen.destroy();
  150. parent.removeView(screen);
  151. }
  152. stack.clear();
  153. }
  154. public boolean canPop() {
  155. return stack.size() > 1 && !isPreviousScreenAttachedToWindow();
  156. }
  157. private boolean isPreviousScreenAttachedToWindow() {
  158. Screen previousScreen = stack.get(stack.size() - 2);
  159. if (previousScreen.getParent() != null) {
  160. Log.w(TAG, "Can't pop stack. reason: previous screen is already attached");
  161. return true;
  162. }
  163. return false;
  164. }
  165. public void setScreenTopBarVisible(String screenInstanceId, final boolean visible, final boolean animate) {
  166. performOnScreen(screenInstanceId, new Task<Screen>() {
  167. @Override
  168. public void run(Screen param) {
  169. param.setTopBarVisible(visible, animate);
  170. }
  171. });
  172. }
  173. public void setScreenTitleBarTitle(String screenInstanceId, final String title) {
  174. performOnScreen(screenInstanceId, new Task<Screen>() {
  175. @Override
  176. public void run(Screen param) {
  177. param.setTitleBarTitle(title);
  178. }
  179. });
  180. }
  181. public void setScreenTitleBarSubtitle(String screenInstanceId, final String subtitle) {
  182. performOnScreen(screenInstanceId, new Task<Screen>() {
  183. @Override
  184. public void run(Screen param) {
  185. param.setTitleBarSubtitle(subtitle);
  186. }
  187. });
  188. }
  189. public void setScreenTitleBarRightButtons(String screenInstanceId, final String navigatorEventId, final List<TitleBarButtonParams> titleBarButtons) {
  190. performOnScreen(screenInstanceId, new Task<Screen>() {
  191. @Override
  192. public void run(Screen param) {
  193. param.setTitleBarRightButtons(navigatorEventId, titleBarButtons);
  194. }
  195. });
  196. }
  197. public void setScreenTitleBarLeftButton(String screenInstanceId, final String navigatorEventId, final TitleBarLeftButtonParams titleBarLeftButtonParams) {
  198. performOnScreen(screenInstanceId, new Task<Screen>() {
  199. @Override
  200. public void run(Screen param) {
  201. param.setTitleBarLeftButton(navigatorEventId, leftButtonOnClickListener, titleBarLeftButtonParams);
  202. }
  203. });
  204. }
  205. public void setFab(String screenInstanceId, final String navigatorEventId, final FabParams fabParams) {
  206. performOnScreen(screenInstanceId, new Task<Screen>() {
  207. @Override
  208. public void run(Screen param) {
  209. param.setFab(fabParams);
  210. }
  211. });
  212. }
  213. public void showContextualMenu(String screenInstanceId, final ContextualMenuParams params, final Callback onButtonClicked) {
  214. performOnScreen(screenInstanceId, new Task<Screen>() {
  215. @Override
  216. public void run(Screen screen) {
  217. screen.showContextualMenu(params, onButtonClicked);
  218. }
  219. });
  220. }
  221. public void dismissContextualMenu(String screenInstanceId) {
  222. performOnScreen(screenInstanceId, new Task<Screen>() {
  223. @Override
  224. public void run(Screen screen) {
  225. screen.dismissContextualMenu();
  226. }
  227. });
  228. }
  229. public StyleParams getCurrentScreenStyleParams() {
  230. return stack.peek().getStyleParams();
  231. }
  232. public boolean handleBackPressInJs() {
  233. ScreenParams currentScreen = stack.peek().screenParams;
  234. if (currentScreen.overrideBackPressInJs) {
  235. NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("backPress", currentScreen.getNavigatorEventId());
  236. return true;
  237. }
  238. return false;
  239. }
  240. private void performOnScreen(String screenInstanceId, Task<Screen> task) {
  241. if (stack.isEmpty()) {
  242. return;
  243. }
  244. for (Screen screen : stack) {
  245. if (screen.getScreenInstanceId().equals(screenInstanceId)) {
  246. task.run(screen);
  247. return;
  248. }
  249. }
  250. }
  251. public void show() {
  252. isStackVisible = true;
  253. stack.peek().setStyle();
  254. stack.peek().setVisibility(View.VISIBLE);
  255. }
  256. public void hide() {
  257. isStackVisible = false;
  258. stack.peek().setVisibility(View.INVISIBLE);
  259. }
  260. }