react-native-navigation的迁移库

RctView.java 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package com.reactnativenavigation.views;
  2. import android.os.Bundle;
  3. import android.util.Log;
  4. import android.view.View;
  5. import android.view.ViewGroup;
  6. import android.view.ViewTreeObserver;
  7. import android.widget.FrameLayout;
  8. import android.widget.ScrollView;
  9. import com.facebook.react.ReactInstanceManager;
  10. import com.facebook.react.ReactRootView;
  11. import com.reactnativenavigation.activities.BaseReactActivity;
  12. import com.reactnativenavigation.activities.BottomTabActivity;
  13. import com.reactnativenavigation.core.objects.Screen;
  14. import com.reactnativenavigation.utils.BridgeUtils;
  15. import com.reactnativenavigation.utils.ReflectionUtils;
  16. /**
  17. * Created by guyc on 10/03/16.
  18. */
  19. public class RctView extends FrameLayout {
  20. private static final String TAG = "RctView";
  21. private BottomTabActivity mContext;
  22. private ReactRootView mReactRootView;
  23. private ScrollView mScrollView;
  24. private int mLastScrollY = -1;
  25. private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener = new ViewTreeObserver.OnScrollChangedListener() {
  26. @Override
  27. public void onScrollChanged() {
  28. if (!mScrollView.getViewTreeObserver().isAlive()) {
  29. return;
  30. }
  31. final int scrollY = mScrollView.getScrollY();
  32. if (scrollY != mLastScrollY && // Scroll position changed
  33. scrollY > 0 && // Ignore top overscroll
  34. scrollY < (mScrollView.getChildAt(0).getHeight() - mScrollView.getHeight())) { // Ignore bottom overscroll
  35. int direction = scrollY > mLastScrollY ?
  36. BottomNavigation.SCROLL_DIRECTION_DOWN :
  37. BottomNavigation.SCROLL_DIRECTION_UP;
  38. mLastScrollY = scrollY;
  39. mContext.onScrollChanged(direction);
  40. }
  41. }
  42. };
  43. private boolean mIsScrollEventListenerRegistered = false;
  44. private final View.OnAttachStateChangeListener mStateChangeListener =
  45. new View.OnAttachStateChangeListener() {
  46. @Override
  47. public void onViewAttachedToWindow(View v) {
  48. Log.d(TAG, "onViewAttachedToWindow " + v.getClass());
  49. mScrollView = getScrollView((ViewGroup) getParent());
  50. if (mScrollView != null && !mIsScrollEventListenerRegistered) {
  51. Log.i(TAG, "setting scroll listener");
  52. addScrollListener();
  53. } else {
  54. Log.v(TAG, "doing nothing");
  55. }
  56. }
  57. @Override
  58. public void onViewDetachedFromWindow(final View detachedView) {
  59. Log.d(TAG, "onViewDetachedFromWindow. Removing scrollChangedListener");
  60. removeScrollListener();
  61. post(new Runnable() {
  62. @Override
  63. public void run() {
  64. mScrollView = getScrollView((ViewGroup) getParent());
  65. if (mScrollView != null && !mIsScrollEventListenerRegistered) {
  66. Log.i(TAG, "run: setting scroll listener");
  67. mIsScrollEventListenerRegistered = true;
  68. addScrollListener();
  69. } else {
  70. Log.v(TAG, "doing nothing");
  71. }
  72. }
  73. });
  74. }
  75. };
  76. /**
  77. * Interface used to run some code when the {@link ReactRootView} is visible.
  78. */
  79. public interface OnDisplayedListener {
  80. /**
  81. * This method will be invoked when the {@link ReactRootView} is visible.
  82. */
  83. void onDisplayed();
  84. }
  85. @SuppressWarnings("unchecked")
  86. public RctView(BaseReactActivity ctx, ReactInstanceManager rctInstanceManager, final Screen screen,
  87. final OnDisplayedListener onDisplayedListener) {
  88. super(ctx);
  89. setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
  90. OnDisplayedListener onDisplayedListenerInternal = onDisplayedListener;
  91. if (screen.bottomTabsHiddenOnScroll) {
  92. onDisplayedListenerInternal = new OnDisplayedListener() {
  93. @Override
  94. public void onDisplayed() {
  95. if (onDisplayedListener != null) {
  96. onDisplayedListener.onDisplayed();
  97. }
  98. setupScrollViewWithBottomTabs();
  99. }
  100. };
  101. }
  102. mReactRootView = new RnnReactRootView(ctx, onDisplayedListenerInternal);
  103. mReactRootView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
  104. String componentName = screen.screenId;
  105. Bundle passProps = new Bundle();
  106. passProps.putString(Screen.KEY_SCREEN_INSTANCE_ID, screen.screenInstanceId);
  107. passProps.putString(Screen.KEY_NAVIGATOR_ID, screen.navigatorId);
  108. passProps.putString(Screen.KEY_NAVIGATOR_EVENT_ID, screen.navigatorEventId);
  109. if (screen.passedProps != null) {
  110. BridgeUtils.addMapToBundle(screen.passedProps, passProps);
  111. }
  112. mReactRootView.startReactApplication(rctInstanceManager, componentName, passProps);
  113. addView(mReactRootView);
  114. }
  115. private void setupScrollViewWithBottomTabs() {
  116. mScrollView = getScrollView((ViewGroup) getParent());
  117. if (mScrollView != null) {
  118. mContext = (BottomTabActivity) getContext();
  119. attachStateChangeListener(mScrollView);
  120. addScrollListener();
  121. }
  122. }
  123. private ScrollView getScrollView(ViewGroup parent) {
  124. for (int i = 0; i < parent.getChildCount(); i++) {
  125. View child = parent.getChildAt(i);
  126. if (child instanceof ScrollView) {
  127. return (ScrollView) child;
  128. }
  129. if (child instanceof ViewGroup) {
  130. return getScrollView((ViewGroup) child);
  131. }
  132. }
  133. return null;
  134. }
  135. private void attachStateChangeListener(ScrollView scrollView) {
  136. scrollView.addOnAttachStateChangeListener(mStateChangeListener);
  137. }
  138. private void addScrollListener() {
  139. mScrollView.getViewTreeObserver().addOnScrollChangedListener(mScrollChangedListener);
  140. }
  141. private void removeScrollListener() {
  142. mScrollView.getViewTreeObserver().removeOnScrollChangedListener(mScrollChangedListener);
  143. }
  144. /**
  145. * Must be called before view is removed from screen, but will be added again later. Setting mAttachScheduled
  146. * to true will prevent the component from getting unmounted once view is detached from screen.
  147. */
  148. public void onTemporallyRemovedFromScreen() {
  149. // Hack in order to prevent the react view from getting unmounted
  150. ReflectionUtils.setField(mReactRootView, "mAttachScheduled", true);
  151. }
  152. /**
  153. * Must be called before view is removed from screen inorder to ensure onDetachedFromScreen is properly
  154. * executed and componentWillUnmount is called
  155. */
  156. public void onRemoveFromScreen() {
  157. ReflectionUtils.setField(mReactRootView, "mAttachScheduled", false);
  158. }
  159. /**
  160. * Must be called when view is added again to screen inorder to ensure onDetachedFromScreen is properly
  161. * executed and componentWillUnmount is called
  162. */
  163. public void onReAddToScreen() {
  164. ReflectionUtils.setField(mReactRootView, "mAttachScheduled", false);
  165. }
  166. public void detachFromScreen() {
  167. ReflectionUtils.invoke(mReactRootView, "onDetachedFromWindow");
  168. }
  169. }