Daniel Zlotin 8 years ago
parent
commit
0f2bf32a66

+ 1
- 1
android/app/src/main/java/com/reactnativenavigation/screens/FragmentScreen.java View File

@@ -38,7 +38,7 @@ public class FragmentScreen extends Screen {
38 38
     }
39 39
 
40 40
     private void addContent() {
41
-        ContentView contentView = new ContentView(getContext(), screenParams.screenId, screenParams.passProps, screenParams.navigationParams, null);
41
+        ContentView contentView = new ContentView(getContext(), screenParams.screenId, screenParams.passProps, screenParams.navigationParams, topBar);
42 42
         addView(contentView, 0, 0);
43 43
         LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
44 44
         if (screenParams.styleParams.drawScreenBelowTopBar) {

+ 3
- 24
android/app/src/main/java/com/reactnativenavigation/screens/Screen.java View File

@@ -9,14 +9,11 @@ import android.util.Log;
9 9
 import android.view.Window;
10 10
 import android.widget.RelativeLayout;
11 11
 
12
-import com.reactnativenavigation.animation.VisibilityAnimator;
13 12
 import com.reactnativenavigation.params.ScreenParams;
14 13
 import com.reactnativenavigation.params.StyleParams;
15 14
 import com.reactnativenavigation.params.TitleBarButtonParams;
16 15
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
17 16
 import com.reactnativenavigation.utils.SdkSupports;
18
-import com.reactnativenavigation.utils.ViewUtils;
19
-import com.reactnativenavigation.views.ScrollDirectionListener;
20 17
 import com.reactnativenavigation.views.TitleBarBackButtonListener;
21 18
 import com.reactnativenavigation.views.TopBar;
22 19
 
@@ -25,13 +22,12 @@ import java.util.List;
25 22
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
26 23
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
27 24
 
28
-public abstract class Screen extends RelativeLayout implements ScrollDirectionListener.OnScrollChanged {
25
+public abstract class Screen extends RelativeLayout {
29 26
 
30 27
     protected final AppCompatActivity activity;
31 28
     protected final ScreenParams screenParams;
32 29
     protected TopBar topBar;
33 30
     private final TitleBarBackButtonListener titleBarBackButtonListener;
34
-    private VisibilityAnimator topBarVisibilityAnimator;
35 31
 
36 32
     public Screen(AppCompatActivity activity, ScreenParams screenParams, TitleBarBackButtonListener titleBarBackButtonListener) {
37 33
         super(activity);
@@ -59,22 +55,10 @@ public abstract class Screen extends RelativeLayout implements ScrollDirectionLi
59 55
 
60 56
     private void createTopBar() {
61 57
         topBar = new TopBar(getContext());
62
-        createTopBarVisibilityAnimator();
63 58
         addView(topBar, new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
64 59
     }
65 60
 
66
-    private void createTopBarVisibilityAnimator() {
67
-        ViewUtils.runOnPreDraw(topBar, new Runnable() {
68
-            @Override
69
-            public void run() {
70
-                if (topBarVisibilityAnimator == null) {
71
-                    topBarVisibilityAnimator = new VisibilityAnimator(topBar, VisibilityAnimator.HideDirection.Up, topBar.getHeight());
72
-                }
73
-            }
74
-        });
75
-    }
76
-
77
-    private void setStyle(StyleParams styleParams) {
61
+    private void setStyle(ScreenStyleParams styleParams) {
78 62
         setStatusBarColor(styleParams.statusBarColor);
79 63
         setNavigationBarColor(styleParams.navigationBarColor);
80 64
         topBar.setStyle(styleParams);
@@ -122,11 +106,6 @@ public abstract class Screen extends RelativeLayout implements ScrollDirectionLi
122 106
         Log.d("LOG", "Screen.onDetachedFromWindow " + this);
123 107
     }
124 108
 
125
-    @Override
126
-    public void onScrollChanged(ScrollDirectionListener.Direction direction) {
127
-        topBarVisibilityAnimator.onScrollChanged(direction);
128
-    }
129
-
130 109
     public abstract void ensureUnmountOnDetachedFromWindow();
131 110
 
132 111
     public abstract void preventUnmountOnDetachedFromWindow();
@@ -138,7 +117,7 @@ public abstract class Screen extends RelativeLayout implements ScrollDirectionLi
138 117
     }
139 118
 
140 119
     public void setTopBarVisible(boolean visible, boolean animate) {
141
-        topBarVisibilityAnimator.setVisible(visible, animate);
120
+//        topBarVisibilityAnimator.setVisible(visible, animate); TODO
142 121
     }
143 122
 
144 123
     public void setTitleBarTitle(String title) {

+ 1
- 1
android/app/src/main/java/com/reactnativenavigation/screens/SingleScreen.java View File

@@ -19,7 +19,7 @@ public class SingleScreen extends Screen {
19 19
 
20 20
     @Override
21 21
     protected void createContent() {
22
-        contentView = new ContentView(getContext(), screenParams.screenId, screenParams.passProps, screenParams.navigationParams, this);
22
+        contentView = new ContentView(getContext(), screenParams.screenId, screenParams.passProps, screenParams.navigationParams, topBar);
23 23
         LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
24 24
         if (screenParams.styleParams.drawScreenBelowTopBar) {
25 25
             params.addRule(BELOW, topBar.getId());

+ 1
- 2
android/app/src/main/java/com/reactnativenavigation/screens/ViewPagerScreen.java View File

@@ -39,8 +39,7 @@ public class ViewPagerScreen extends Screen {
39 39
             ContentView contentView = new ContentView(getContext(),
40 40
                     topTabParam.screenId,
41 41
                     screenParams.passProps,
42
-                    screenParams.navigationParams,
43
-                    this);
42
+                    screenParams.navigationParams, topBar);
44 43
             addContent(contentView);
45 44
             contentViews.add(contentView);
46 45
         }

+ 4
- 0
android/app/src/main/java/com/reactnativenavigation/utils/SdkSupports.java View File

@@ -7,4 +7,8 @@ public class SdkSupports {
7 7
     public static boolean lollipop() {
8 8
         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
9 9
     }
10
+
11
+    public static boolean marshmallow() {
12
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
13
+    }
10 14
 }

+ 47
- 8
android/app/src/main/java/com/reactnativenavigation/views/ContentView.java View File

@@ -3,6 +3,7 @@ package com.reactnativenavigation.views;
3 3
 import android.content.Context;
4 4
 import android.os.Bundle;
5 5
 import android.view.View;
6
+import android.widget.ScrollView;
6 7
 
7 8
 import com.facebook.react.ReactInstanceManager;
8 9
 import com.facebook.react.ReactRootView;
@@ -14,17 +15,57 @@ public class ContentView extends ReactRootView {
14 15
     private final String screenId;
15 16
     private final Bundle passProps;
16 17
     private Bundle navigationParams;
17
-    private ScrollViewAttacher scrollViewAttacher;
18
+    private ScrollViewDelegate scrollViewDelegate = new ScrollViewDelegate();
18 19
 
19
-    public ContentView(Context context, String screenId, Bundle passProps, Bundle navigationParams, ScrollDirectionListener.OnScrollChanged scrollListener) {
20
+    public ContentView(Context context, final String screenId, Bundle passProps, Bundle navigationParams, final TopBar topBar) {
20 21
         super(context);
21 22
         this.screenId = screenId;
22 23
         this.passProps = passProps;
23 24
         this.navigationParams = navigationParams;
24
-        if (scrollListener != null) {
25
-            scrollViewAttacher = new ScrollViewAttacher(scrollListener);
26
-        }
27 25
         attachToJS();
26
+
27
+        scrollViewDelegate.setListener(new ScrollViewDelegate.OnScrollListener() {
28
+
29
+            private ScrollDirection scrollDirectionComputer;
30
+
31
+
32
+            @Override
33
+            public void onScroll(ScrollView scrollView) {
34
+                /**
35
+                 * do our magic
36
+                 */
37
+                if (scrollDirectionComputer == null) {
38
+                    scrollDirectionComputer = new ScrollDirection(scrollView);
39
+                }
40
+
41
+                int currentTopBarTranslation = (int) topBar.getTranslationY();
42
+                int delta = scrollDirectionComputer.getScrollDelta();
43
+
44
+                int minTranslation = -topBar.getTitleBar().getHeight();
45
+                int maxTranslation = 0;
46
+
47
+                ScrollDirection.Direction direction = scrollDirectionComputer.getScrollDirection();
48
+
49
+                boolean reachedMinimum = direction == ScrollDirection.Direction.Up && currentTopBarTranslation <= minTranslation;
50
+                boolean reachedMaximum = direction == ScrollDirection.Direction.Down && currentTopBarTranslation >= maxTranslation;
51
+
52
+                if (direction == ScrollDirection.Direction.None || reachedMinimum || reachedMaximum) {
53
+                    if (reachedMinimum) {
54
+                        topBar.animate().translationY(minTranslation);
55
+                    }
56
+                    if (reachedMaximum) {
57
+                        topBar.animate().translationY(maxTranslation);
58
+                    }
59
+                } else {
60
+
61
+                    int target = currentTopBarTranslation - delta;
62
+                    int bound = Math.min(Math.max(minTranslation, target), maxTranslation);
63
+
64
+                    topBar.setTranslationY(bound);
65
+                }
66
+
67
+            }
68
+        });
28 69
     }
29 70
 
30 71
     private void attachToJS() {
@@ -35,9 +76,7 @@ public class ContentView extends ReactRootView {
35 76
     @Override
36 77
     public void onViewAdded(View child) {
37 78
         super.onViewAdded(child);
38
-        if (scrollViewAttacher != null) {
39
-            scrollViewAttacher.onViewAdded(child);
40
-        }
79
+        scrollViewDelegate.onViewAdded(child);
41 80
     }
42 81
 
43 82
     private Bundle mergePropsAndNavigationParams() {

+ 50
- 0
android/app/src/main/java/com/reactnativenavigation/views/ScrollDirection.java View File

@@ -0,0 +1,50 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.widget.ScrollView;
4
+
5
+public class ScrollDirection {
6
+
7
+    public enum Direction {
8
+        Up, Down, None
9
+    }
10
+
11
+    private final ScrollView scrollView;
12
+    private int lastScrollY = 0;
13
+
14
+    public ScrollDirection(ScrollView scrollView) {
15
+        this.scrollView = scrollView;
16
+    }
17
+
18
+    public Direction getScrollDirection() {
19
+        Direction direction = Direction.None;
20
+
21
+        final int scrollY = scrollView.getScrollY();
22
+        if (isScrollPositionChanged(scrollY) && !isTopOverscroll(scrollY) && !isBottomOverscroll(scrollY)) {
23
+            direction = getScrollDirection(scrollY);
24
+            lastScrollY = scrollY;
25
+        }
26
+        return direction;
27
+    }
28
+
29
+    public int getScrollDelta() {
30
+        return scrollView.getScrollY() - lastScrollY;
31
+    }
32
+
33
+
34
+    private Direction getScrollDirection(int scrollY) {
35
+        return scrollY > lastScrollY ? Direction.Up : Direction.Down;
36
+    }
37
+
38
+    private boolean isBottomOverscroll(int scrollY) {
39
+        return scrollY >= (scrollView.getChildAt(0).getHeight() - scrollView.getHeight());
40
+    }
41
+
42
+    private boolean isTopOverscroll(int scrollY) {
43
+        return scrollY <= 0;
44
+    }
45
+
46
+    private boolean isScrollPositionChanged(int scrollY) {
47
+        return scrollY != lastScrollY;
48
+    }
49
+
50
+}

+ 0
- 32
android/app/src/main/java/com/reactnativenavigation/views/ScrollViewAttacher.java View File

@@ -1,32 +0,0 @@
1
-package com.reactnativenavigation.views;
2
-
3
-import android.view.View;
4
-import android.widget.ScrollView;
5
-
6
-public class ScrollViewAttacher {
7
-
8
-    private final ScrollDirectionListener.OnScrollChanged onChanged;
9
-    private ScrollView scrollView;
10
-    private ScrollDirectionListener scrollDirectionListener;
11
-
12
-    public ScrollViewAttacher(ScrollDirectionListener.OnScrollChanged onChanged) {
13
-        this.onChanged = onChanged;
14
-    }
15
-
16
-    public void onViewAdded(View child) {
17
-        if (child instanceof ScrollView) {
18
-            detach();
19
-            scrollView = (ScrollView) child;
20
-            scrollDirectionListener = new ScrollDirectionListener(scrollView, onChanged);
21
-            scrollView.getViewTreeObserver().addOnScrollChangedListener(scrollDirectionListener);
22
-        }
23
-    }
24
-
25
-    private void detach() {
26
-        if (scrollView != null) {
27
-            scrollView.getViewTreeObserver().removeOnScrollChangedListener(scrollDirectionListener);
28
-            scrollDirectionListener = null;
29
-            scrollView = null;
30
-        }
31
-    }
32
-}

+ 59
- 0
android/app/src/main/java/com/reactnativenavigation/views/ScrollViewDelegate.java View File

@@ -0,0 +1,59 @@
1
+package com.reactnativenavigation.views;
2
+
3
+import android.view.View;
4
+import android.view.ViewTreeObserver;
5
+import android.widget.ScrollView;
6
+
7
+import com.reactnativenavigation.utils.SdkSupports;
8
+
9
+public class ScrollViewDelegate implements ViewTreeObserver.OnScrollChangedListener {
10
+
11
+    public interface OnScrollListener {
12
+        void onScroll(ScrollView scrollView);
13
+    }
14
+
15
+    private ScrollView scrollView;
16
+    private OnScrollListener listener;
17
+
18
+    public ScrollViewDelegate() {
19
+    }
20
+
21
+    public void onViewAdded(View child) {
22
+        if (child instanceof ScrollView) {
23
+            detach();
24
+            scrollView = (ScrollView) child;
25
+            if (SdkSupports.marshmallow()) {
26
+                scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
27
+                    @Override
28
+                    public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
29
+                        ScrollViewDelegate.this.onScrollChanged();
30
+                    }
31
+                });
32
+            } else {
33
+                scrollView.getViewTreeObserver().addOnScrollChangedListener(this);
34
+            }
35
+        }
36
+    }
37
+
38
+    private void detach() {
39
+        if (scrollView != null) {
40
+            if (SdkSupports.marshmallow()) {
41
+                scrollView.setOnScrollChangeListener(null);
42
+            } else {
43
+                scrollView.getViewTreeObserver().removeOnScrollChangedListener(this);
44
+            }
45
+            scrollView = null;
46
+        }
47
+    }
48
+
49
+    public void setListener(OnScrollListener listener) {
50
+        this.listener = listener;
51
+    }
52
+
53
+    @Override
54
+    public void onScrollChanged() {
55
+        if (this.listener != null) {
56
+            this.listener.onScroll(scrollView);
57
+        }
58
+    }
59
+}

+ 4
- 0
android/app/src/main/java/com/reactnativenavigation/views/TopBar.java View File

@@ -58,4 +58,8 @@ public class TopBar extends AppBarLayout {
58 58
                                        TitleBarLeftButtonParams titleBarLeftButtonParams) {
59 59
         titleBar.setLeftButton(titleBarLeftButtonParams, titleBarBackButtonListener, navigatorEventId);
60 60
     }
61
+
62
+    public TitleBar getTitleBar() {
63
+        return titleBar;
64
+    }
61 65
 }