Browse Source

Fling collapsing react view screens (#1213)

Guy Carmeli 7 years ago
parent
commit
a2a9324b1e

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

@@ -81,9 +81,9 @@ public class CollapsingSingleScreen extends SingleScreen {
81 81
                     @Override
82 82
                     public void onFling(CollapseAmount amount) {
83 83
                         if (screenParams.styleParams.drawScreenBelowTopBar) {
84
-                            ((CollapsingView) contentView).collapse(amount);
84
+                            ((CollapsingView) contentView).fling(amount);
85 85
                         }
86
-                        topBar.collapse(amount);
86
+                        topBar.fling(amount);
87 87
                     }
88 88
                 },
89 89
                 getCollapseBehaviour()

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

@@ -80,8 +80,8 @@ public class CollapsingViewPagerScreen extends ViewPagerScreen {
80 80
 
81 81
                     @Override
82 82
                     public void onFling(CollapseAmount amount) {
83
-                        topBar.collapse(amount);
84
-                        ((CollapsingView) viewPager).collapse(amount);
83
+                        topBar.fling(amount);
84
+                        ((CollapsingView) viewPager).fling(amount);
85 85
                     }
86 86
                 },
87 87
                 getCollapseBehaviour()

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/views/CollapsingContentView.java View File

@@ -57,6 +57,11 @@ public class CollapsingContentView extends ContentView implements CollapsingView
57 57
         viewCollapser.collapse(amount);
58 58
     }
59 59
 
60
+    @Override
61
+    public void fling(CollapseAmount amount) {
62
+        viewCollapser.fling(amount);
63
+    }
64
+
60 65
     public void destroy() {
61 66
         if (scrollViewDetector != null) {
62 67
             scrollViewDetector.destroy();

+ 2
- 2
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseAmount.java View File

@@ -24,11 +24,11 @@ public class CollapseAmount {
24 24
         return amount != null;
25 25
     }
26 26
 
27
-    public boolean collapseToTop() {
27
+    boolean collapseToTop() {
28 28
         return direction == CollapseCalculator.Direction.Up;
29 29
     }
30 30
 
31
-    public boolean collapseToBottom() {
31
+    boolean collapseToBottom() {
32 32
         return direction == CollapseCalculator.Direction.Down;
33 33
     }
34 34
 

+ 29
- 8
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseCalculator.java View File

@@ -2,6 +2,7 @@ package com.reactnativenavigation.views.collapsingToolbar;
2 2
 
3 3
 import android.support.annotation.NonNull;
4 4
 import android.support.annotation.Nullable;
5
+import android.util.Log;
5 6
 import android.view.GestureDetector;
6 7
 import android.view.MotionEvent;
7 8
 import android.view.ViewConfiguration;
@@ -12,6 +13,9 @@ import com.reactnativenavigation.views.collapsingToolbar.behaviours.CollapseBeha
12 13
 import com.reactnativenavigation.views.collapsingToolbar.behaviours.TitleBarHideOnScrollBehaviour;
13 14
 
14 15
 public class CollapseCalculator {
16
+    private static final int FLING_DISTANCE_PIXELS_THRESHOLD = 100;
17
+    private static final int FLING_VELOCITY = 7000;
18
+
15 19
     public enum Direction {
16 20
         Up, Down, None
17 21
     }
@@ -32,12 +36,12 @@ public class CollapseCalculator {
32 36
     private int scrollY = 0;
33 37
     private float totalCollapse = 0;
34 38
     private float totalCollapseDeltaSinceTouchDown = 0;
35
-    private final int scaledTouchSlop;
39
+    private final ViewConfiguration viewConfiguration;
36 40
 
37 41
     public CollapseCalculator(final CollapsingView collapsingView, CollapseBehaviour collapseBehaviour) {
38 42
         this.view = collapsingView;
39 43
         this.collapseBehaviour = collapseBehaviour;
40
-        scaledTouchSlop = ViewConfiguration.get(NavigationApplication.instance).getScaledTouchSlop();
44
+        viewConfiguration = ViewConfiguration.get(NavigationApplication.instance);
41 45
         setFlingDetector();
42 46
     }
43 47
 
@@ -46,10 +50,27 @@ public class CollapseCalculator {
46 50
             flingDetector =
47 51
                     new GestureDetector(NavigationApplication.instance, new GestureDetector.SimpleOnGestureListener() {
48 52
                         @Override
49
-                        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
53
+                        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, final float velocityY) {
50 54
                             final Direction direction = getScrollDirection(e1, e2);
55
+                            final float diff = Math.abs(e2.getRawY() - e1.getRawY());
56
+                            if (Math.abs(velocityY) < viewConfiguration.getScaledMinimumFlingVelocity() ||
57
+                                diff < FLING_DISTANCE_PIXELS_THRESHOLD) {
58
+                                Log.w("FLING", "Consuming fling v: [" + velocityY + "] dy: [" + diff + "]");
59
+                                return false;
60
+                            }
61
+
51 62
                             if (canCollapse(direction) && totalCollapse != 0) {
52 63
                                 flingListener.onFling(new CollapseAmount(direction));
64
+                                if (direction == Direction.Up) {
65
+                                    scrollView.postDelayed(new Runnable() {
66
+                                        @Override
67
+                                        public void run() {
68
+                                            int max = (int) Math.max(Math.abs(velocityY), FLING_VELOCITY);
69
+                                            scrollView.fling(max);
70
+                                        }
71
+                                    }, ViewCollapser.FLING_DURATION);
72
+                                }
73
+
53 74
                                 return true;
54 75
                             }
55 76
                             return false;
@@ -76,7 +97,8 @@ public class CollapseCalculator {
76 97
     @NonNull
77 98
     CollapseAmount calculate(MotionEvent event) {
78 99
         updateInitialTouchY(event);
79
-        CollapseAmount touchUpCollapse = shouldCollapseOnTouchUp(event);
100
+        final boolean isFling = flingDetector.onTouchEvent(event);
101
+        CollapseAmount touchUpCollapse = shouldCollapseOnTouchUp(event, isFling);
80 102
         if (touchUpCollapse != CollapseAmount.None) {
81 103
             previousTouchEvent = MotionEvent.obtain(event);
82 104
             return touchUpCollapse;
@@ -97,9 +119,8 @@ public class CollapseCalculator {
97 119
         }
98 120
     }
99 121
 
100
-    private CollapseAmount shouldCollapseOnTouchUp(MotionEvent event) {
101
-        if ((collapseBehaviour.shouldCollapseOnTouchUp())
102
-            && !flingDetector.onTouchEvent(event) && isTouchUp(event)) {
122
+    private CollapseAmount shouldCollapseOnTouchUp(MotionEvent event, boolean isFling) {
123
+        if (isTouchUp(event) && collapseBehaviour.shouldCollapseOnTouchUp() && !isFling) {
103 124
             final float visibilityPercentage = view.getCurrentCollapseValue() / view.getFinalCollapseValue();
104 125
             Direction direction = visibilityPercentage >= 0.5f ? Direction.Up : Direction.Down;
105 126
             if (canCollapse(direction) && totalCollapse != 0) {
@@ -195,7 +216,7 @@ public class CollapseCalculator {
195 216
         totalCollapseDeltaSinceTouchDown += Math.abs(y - previousCollapseY);
196 217
         previousCollapseY = y;
197 218
         previousTouchEvent = MotionEvent.obtain(event);
198
-        return totalCollapseDeltaSinceTouchDown < scaledTouchSlop ? CollapseAmount.None : new CollapseAmount(collapse);
219
+        return totalCollapseDeltaSinceTouchDown < viewConfiguration.getScaledTouchSlop() ? CollapseAmount.None : new CollapseAmount(collapse);
199 220
     }
200 221
 
201 222
     private float calculateCollapse(float y) {

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBar.java View File

@@ -138,6 +138,11 @@ public class CollapsingTopBar extends TopBar implements CollapsingView {
138 138
         }
139 139
     }
140 140
 
141
+    @Override
142
+    public void fling(CollapseAmount amount) {
143
+        viewCollapser.fling(amount, (CollapsingTitleBar) titleBar, header);
144
+    }
145
+
141 146
     public void onScrollViewAdded(ScrollView scrollView) {
142 147
         scrollListener.onScrollViewAdded(scrollView);
143 148
     }

+ 1
- 0
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBarReactHeader.java View File

@@ -115,6 +115,7 @@ public class CollapsingTopBarReactHeader extends ContentView implements Collapsi
115 115
     }
116 116
 
117 117
     private void onTouchDown(MotionEvent ev) {
118
+        listener.onTouch(ev);
118 119
         if (touchDown == -1) {
119 120
             touchDown = (int) ev.getRawY();
120 121
         }

+ 2
- 0
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingView.java View File

@@ -10,4 +10,6 @@ public interface CollapsingView {
10 10
     View asView();
11 11
 
12 12
     void collapse(CollapseAmount amount);
13
+
14
+    void fling(CollapseAmount amount);
13 15
 }

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingViewPager.java View File

@@ -43,4 +43,9 @@ public class CollapsingViewPager extends ViewPager implements CollapsingView {
43 43
     public void collapse(CollapseAmount amount) {
44 44
         viewCollapser.collapse(amount);
45 45
     }
46
+
47
+    @Override
48
+    public void fling(CollapseAmount amount) {
49
+        viewCollapser.fling(amount);
50
+    }
46 51
 }

+ 40
- 0
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ViewCollapser.java View File

@@ -2,12 +2,24 @@ package com.reactnativenavigation.views.collapsingToolbar;
2 2
 
3 3
 import android.animation.Animator;
4 4
 import android.animation.AnimatorListenerAdapter;
5
+import android.animation.ObjectAnimator;
6
+import android.animation.ValueAnimator;
7
+import android.support.annotation.NonNull;
8
+import android.view.View;
5 9
 import android.view.ViewPropertyAnimator;
10
+import android.view.animation.DecelerateInterpolator;
6 11
 
7 12
 public class ViewCollapser {
8 13
     private static final int DURATION = 160;
14
+    public static final int FLING_DURATION = 40;
9 15
     private CollapsingView view;
10 16
     private ViewPropertyAnimator animator;
17
+    private final ValueAnimator.AnimatorUpdateListener LISTENER =
18
+            new ValueAnimator.AnimatorUpdateListener() {
19
+                @Override
20
+                public void onAnimationUpdate(ValueAnimator animation) {
21
+                }
22
+            };
11 23
 
12 24
     public ViewCollapser(CollapsingView view) {
13 25
         this.view = view;
@@ -55,4 +67,32 @@ public class ViewCollapser {
55 67
                 });
56 68
         animator.start();
57 69
     }
70
+
71
+    void fling(final CollapseAmount amount, final CollapsingTitleBar titleBar, final CollapsingTopBarReactHeader header) {
72
+        fling(amount, new ValueAnimator.AnimatorUpdateListener() {
73
+            @Override
74
+            public void onAnimationUpdate(ValueAnimator animation) {
75
+                titleBar.collapse(new CollapseAmount((Float) animation.getAnimatedValue()));
76
+                header.collapse((Float) animation.getAnimatedValue());
77
+            }
78
+        });
79
+    }
80
+
81
+    public void fling(CollapseAmount amount) {
82
+        fling(amount, LISTENER);
83
+    }
84
+
85
+    private void fling(final CollapseAmount amount, @NonNull final ValueAnimator.AnimatorUpdateListener updateListener) {
86
+        final float translation = amount.collapseToTop() ? view.getFinalCollapseValue() : 0;
87
+        ObjectAnimator animator = ObjectAnimator.ofFloat(view.asView(), View.TRANSLATION_Y, translation);
88
+        animator.setDuration(FLING_DURATION);
89
+        animator.setInterpolator(new DecelerateInterpolator());
90
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
91
+            @Override
92
+            public void onAnimationUpdate(ValueAnimator animation) {
93
+                updateListener.onAnimationUpdate(animation);
94
+            }
95
+        });
96
+        animator.start();
97
+    }
58 98
 }

+ 1
- 1
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/CollapseTopBarBehaviour.java View File

@@ -3,7 +3,7 @@ package com.reactnativenavigation.views.collapsingToolbar.behaviours;
3 3
 public class CollapseTopBarBehaviour implements CollapseBehaviour {
4 4
     @Override
5 5
     public boolean shouldCollapseOnFling() {
6
-        return false;
6
+        return true;
7 7
     }
8 8
 
9 9
     @Override