浏览代码

Search android (#432)

* Move event emmiter logic out of Application

* Implement searchView

Usage:
```js
rightButtons: [
      {
        id: 'searchView',
        label: 'Search',
        hint: 'Search...'
      }
    ]
```

* Translucent TitleBar

* Collapse TopBar

* Less noticeable translucent effect

* Implement ScrollViewDetector

* Collapse on fling

* Collapse on touch up

Complete collapse on touch up instead of fling
Guy Carmeli 8 年前
父节点
当前提交
c10f41ff0e
共有 47 个文件被更改,包括 826 次插入259 次删除
  1. 7
    30
      android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java
  2. 41
    0
      android/app/src/main/java/com/reactnativenavigation/bridge/EventEmitter.java
  3. 1
    1
      android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java
  4. 1
    1
      android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java
  5. 10
    1
      android/app/src/main/java/com/reactnativenavigation/params/CollapsingTopBarParams.java
  6. 2
    0
      android/app/src/main/java/com/reactnativenavigation/params/StyleParams.java
  7. 1
    0
      android/app/src/main/java/com/reactnativenavigation/params/TitleBarButtonParams.java
  8. 13
    9
      android/app/src/main/java/com/reactnativenavigation/params/parsers/CollapsingTopBarParamsParser.java
  9. 6
    6
      android/app/src/main/java/com/reactnativenavigation/params/parsers/Parser.java
  10. 11
    0
      android/app/src/main/java/com/reactnativenavigation/params/parsers/StyleParamsParser.java
  11. 5
    3
      android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarButtonParamsParser.java
  12. 41
    22
      android/app/src/main/java/com/reactnativenavigation/screens/CollapsingSingleScreen.java
  13. 1
    1
      android/app/src/main/java/com/reactnativenavigation/screens/ContentViewPagerAdapter.java
  14. 2
    6
      android/app/src/main/java/com/reactnativenavigation/screens/ScreenStack.java
  15. 36
    0
      android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java
  16. 18
    0
      android/app/src/main/java/com/reactnativenavigation/views/ButtonFactory.java
  17. 79
    0
      android/app/src/main/java/com/reactnativenavigation/views/CollapsingContentView.java
  18. 1
    42
      android/app/src/main/java/com/reactnativenavigation/views/ContentView.java
  19. 1
    1
      android/app/src/main/java/com/reactnativenavigation/views/ContextualMenu.java
  20. 3
    3
      android/app/src/main/java/com/reactnativenavigation/views/FloatingActionButtonCoordinator.java
  21. 9
    9
      android/app/src/main/java/com/reactnativenavigation/views/LeftButton.java
  22. 5
    5
      android/app/src/main/java/com/reactnativenavigation/views/Snakbar.java
  23. 8
    1
      android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java
  24. 4
    4
      android/app/src/main/java/com/reactnativenavigation/views/TitleBarButton.java
  25. 156
    0
      android/app/src/main/java/com/reactnativenavigation/views/TitleBarSearchButton.java
  26. 0
    1
      android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  27. 36
    0
      android/app/src/main/java/com/reactnativenavigation/views/TranslucentTitleBarBackground.java
  28. 17
    5
      android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseAmount.java
  29. 99
    20
      android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseCalculator.java
  30. 38
    14
      android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBar.java
  31. 5
    0
      android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnFlingListener.java
  32. 5
    0
      android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnScrollListener.java
  33. 0
    50
      android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollDirection.java
  34. 13
    13
      android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollListener.java
  35. 18
    11
      android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollViewDelegate.java
  36. 57
    0
      android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ViewCollapser.java
  37. 64
    0
      android/app/src/main/java/com/reactnativenavigation/views/utils/ScrollViewDetector.java
  38. 二进制
      android/app/src/main/res/drawable-hdpi/ic_action_name.png
  39. 二进制
      android/app/src/main/res/drawable-hdpi/search.png
  40. 二进制
      android/app/src/main/res/drawable-mdpi/ic_action_name.png
  41. 二进制
      android/app/src/main/res/drawable-mdpi/search.png
  42. 二进制
      android/app/src/main/res/drawable-xhdpi/ic_action_name.png
  43. 二进制
      android/app/src/main/res/drawable-xhdpi/search.png
  44. 二进制
      android/app/src/main/res/drawable-xxhdpi/ic_action_name.png
  45. 二进制
      android/app/src/main/res/drawable-xxhdpi/search.png
  46. 10
    0
      android/app/src/main/res/menu/search_item.xml
  47. 2
    0
      src/deprecated/platformSpecificDeprecated.android.js

+ 7
- 30
android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java 查看文件

8
 import com.facebook.react.ReactNativeHost;
8
 import com.facebook.react.ReactNativeHost;
9
 import com.facebook.react.ReactPackage;
9
 import com.facebook.react.ReactPackage;
10
 import com.facebook.react.bridge.ReactContext;
10
 import com.facebook.react.bridge.ReactContext;
11
-import com.facebook.react.bridge.WritableMap;
11
+import com.reactnativenavigation.bridge.EventEmitter;
12
 import com.reactnativenavigation.controllers.ActivityCallbacks;
12
 import com.reactnativenavigation.controllers.ActivityCallbacks;
13
 import com.reactnativenavigation.react.NavigationReactGateway;
13
 import com.reactnativenavigation.react.NavigationReactGateway;
14
 import com.reactnativenavigation.react.ReactGateway;
14
 import com.reactnativenavigation.react.ReactGateway;
20
     public static NavigationApplication instance;
20
     public static NavigationApplication instance;
21
 
21
 
22
     private NavigationReactGateway reactGateway;
22
     private NavigationReactGateway reactGateway;
23
+    private EventEmitter eventEmitter;
23
     private Handler handler;
24
     private Handler handler;
24
     private ActivityCallbacks activityCallbacks;
25
     private ActivityCallbacks activityCallbacks;
25
 
26
 
29
         instance = this;
30
         instance = this;
30
         handler = new Handler(getMainLooper());
31
         handler = new Handler(getMainLooper());
31
         reactGateway = new NavigationReactGateway();
32
         reactGateway = new NavigationReactGateway();
33
+        eventEmitter = new EventEmitter(reactGateway);
32
         activityCallbacks = new ActivityCallbacks();
34
         activityCallbacks = new ActivityCallbacks();
33
     }
35
     }
34
 
36
 
69
         return reactGateway.getReactNativeHost();
71
         return reactGateway.getReactNativeHost();
70
     }
72
     }
71
 
73
 
74
+    public EventEmitter getEventEmitter() {
75
+        return eventEmitter;
76
+    }
77
+
72
     /**
78
     /**
73
      * @see ReactNativeHost#getJSMainModuleName()
79
      * @see ReactNativeHost#getJSMainModuleName()
74
      */
80
      */
97
 
103
 
98
     @Nullable
104
     @Nullable
99
     public abstract List<ReactPackage> createAdditionalReactPackages();
105
     public abstract List<ReactPackage> createAdditionalReactPackages();
100
-
101
-    //TODO move all these navigator junk elsewhere
102
-    public void sendNavigatorEvent(String eventId, String navigatorEventId) {
103
-        if (!isReactContextInitialized()) {
104
-            return;
105
-        }
106
-        reactGateway.getReactEventEmitter().sendNavigatorEvent(eventId, navigatorEventId);
107
-    }
108
-
109
-    public void sendNavigatorEvent(String eventId, String navigatorEventId, WritableMap data) {
110
-        if (!isReactContextInitialized()) {
111
-            return;
112
-        }
113
-        reactGateway.getReactEventEmitter().sendNavigatorEvent(eventId, navigatorEventId, data);
114
-    }
115
-
116
-    public void sendEvent(String eventId, String navigatorEventId) {
117
-        if (!isReactContextInitialized()) {
118
-            return;
119
-        }
120
-        reactGateway.getReactEventEmitter().sendEvent(eventId, navigatorEventId);
121
-    }
122
-
123
-    public void sendNavigatorEvent(String eventId, WritableMap arguments) {
124
-        if (!isReactContextInitialized()) {
125
-            return;
126
-        }
127
-        reactGateway.getReactEventEmitter().sendEvent(eventId, arguments);
128
-    }
129
 }
106
 }

+ 41
- 0
android/app/src/main/java/com/reactnativenavigation/bridge/EventEmitter.java 查看文件

1
+package com.reactnativenavigation.bridge;
2
+
3
+import com.facebook.react.bridge.WritableMap;
4
+import com.reactnativenavigation.NavigationApplication;
5
+import com.reactnativenavigation.react.ReactGateway;
6
+
7
+public class EventEmitter {
8
+    private ReactGateway reactGateway;
9
+
10
+    public EventEmitter(ReactGateway reactGateway) {
11
+        this.reactGateway = reactGateway;
12
+    }
13
+
14
+    public void sendNavigatorEvent(String eventId, String navigatorEventId) {
15
+        if (!NavigationApplication.instance.isReactContextInitialized()) {
16
+            return;
17
+        }
18
+        reactGateway.getReactEventEmitter().sendNavigatorEvent(eventId, navigatorEventId);
19
+    }
20
+
21
+    public void sendNavigatorEvent(String eventId, String navigatorEventId, WritableMap data) {
22
+        if (!NavigationApplication.instance.isReactContextInitialized()) {
23
+            return;
24
+        }
25
+        reactGateway.getReactEventEmitter().sendNavigatorEvent(eventId, navigatorEventId, data);
26
+    }
27
+
28
+    public void sendEvent(String eventId, String navigatorEventId) {
29
+        if (!NavigationApplication.instance.isReactContextInitialized()) {
30
+            return;
31
+        }
32
+        reactGateway.getReactEventEmitter().sendEvent(eventId, navigatorEventId);
33
+    }
34
+
35
+    public void sendNavigatorEvent(String eventId, WritableMap arguments) {
36
+        if (!NavigationApplication.instance.isReactContextInitialized()) {
37
+            return;
38
+        }
39
+        reactGateway.getReactEventEmitter().sendEvent(eventId, arguments);
40
+    }
41
+}

+ 1
- 1
android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java 查看文件

366
             sideMenu.openDrawer();
366
             sideMenu.openDrawer();
367
         } else {
367
         } else {
368
             final String navigatorEventId = getCurrentScreenStack().peek().getNavigatorEventId();
368
             final String navigatorEventId = getCurrentScreenStack().peek().getNavigatorEventId();
369
-            NavigationApplication.instance.sendNavigatorEvent("sideMenu", navigatorEventId);
369
+            NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("sideMenu", navigatorEventId);
370
         }
370
         }
371
     }
371
     }
372
 }
372
 }

+ 1
- 1
android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java 查看文件

236
             sideMenu.openDrawer();
236
             sideMenu.openDrawer();
237
         } else {
237
         } else {
238
             final String navigatorEventId = stack.peek().getNavigatorEventId();
238
             final String navigatorEventId = stack.peek().getNavigatorEventId();
239
-            NavigationApplication.instance.sendNavigatorEvent("sideMenu", navigatorEventId);
239
+            NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("sideMenu", navigatorEventId);
240
         }
240
         }
241
     }
241
     }
242
 }
242
 }

+ 10
- 1
android/app/src/main/java/com/reactnativenavigation/params/CollapsingTopBarParams.java 查看文件

1
 package com.reactnativenavigation.params;
1
 package com.reactnativenavigation.params;
2
 
2
 
3
+import android.support.annotation.Nullable;
4
+
3
 public class CollapsingTopBarParams {
5
 public class CollapsingTopBarParams {
4
-    public String imageUri;
6
+    public enum CollapseBehaviour {TitleBarHideOnScroll, CollapseTopBar}
7
+
8
+    public @Nullable String imageUri;
5
     public StyleParams.Color scrimColor;
9
     public StyleParams.Color scrimColor;
10
+    public CollapseBehaviour collapseBehaviour;
11
+
12
+    public boolean hasBackgroundImage() {
13
+        return imageUri != null;
14
+    }
6
 }
15
 }

+ 2
- 0
android/app/src/main/java/com/reactnativenavigation/params/StyleParams.java 查看文件

47
     public boolean drawScreenBelowTopBar;
47
     public boolean drawScreenBelowTopBar;
48
 
48
 
49
     public boolean titleBarHidden;
49
     public boolean titleBarHidden;
50
+    public boolean titleBarHideOnScroll;
50
     public boolean topBarTransparent;
51
     public boolean topBarTransparent;
52
+    public boolean topBarTranslucent;
51
     public Color titleBarTitleColor;
53
     public Color titleBarTitleColor;
52
     public Color titleBarSubtitleColor;
54
     public Color titleBarSubtitleColor;
53
     public Color titleBarButtonColor;
55
     public Color titleBarButtonColor;

+ 1
- 0
android/app/src/main/java/com/reactnativenavigation/params/TitleBarButtonParams.java 查看文件

5
     public StyleParams.Color color;
5
     public StyleParams.Color color;
6
     public StyleParams.Color disabledColor;
6
     public StyleParams.Color disabledColor;
7
     public boolean enabled = true;
7
     public boolean enabled = true;
8
+    public String hint;
8
 
9
 
9
     public void setColorFromScreenStyle(StyleParams.Color titleBarButtonColor) {
10
     public void setColorFromScreenStyle(StyleParams.Color titleBarButtonColor) {
10
         if (!color.hasColor() && titleBarButtonColor.hasColor()) {
11
         if (!color.hasColor() && titleBarButtonColor.hasColor()) {

+ 13
- 9
android/app/src/main/java/com/reactnativenavigation/params/parsers/CollapsingTopBarParamsParser.java 查看文件

4
 import android.os.Bundle;
4
 import android.os.Bundle;
5
 
5
 
6
 import com.reactnativenavigation.params.CollapsingTopBarParams;
6
 import com.reactnativenavigation.params.CollapsingTopBarParams;
7
+import com.reactnativenavigation.params.CollapsingTopBarParams.CollapseBehaviour;
7
 import com.reactnativenavigation.params.StyleParams;
8
 import com.reactnativenavigation.params.StyleParams;
8
 
9
 
9
-public class CollapsingTopBarParamsParser extends Parser {
10
+class CollapsingTopBarParamsParser extends Parser {
10
     private Bundle params;
11
     private Bundle params;
11
 
12
 
12
-    public CollapsingTopBarParamsParser(Bundle params) {
13
+    CollapsingTopBarParamsParser(Bundle params) {
13
         this.params = params;
14
         this.params = params;
14
     }
15
     }
15
 
16
 
16
     public CollapsingTopBarParams parse() {
17
     public CollapsingTopBarParams parse() {
17
-        if (!hasLocalImageResource() && !hasImageUrl()) {
18
+        if (!hasBackgroundImage() && !shouldHideTitleBarOnScroll()) {
18
             return null;
19
             return null;
19
         }
20
         }
20
 
21
 
21
         CollapsingTopBarParams result = new CollapsingTopBarParams();
22
         CollapsingTopBarParams result = new CollapsingTopBarParams();
22
-        if (hasLocalImageResource()) {
23
-            result.imageUri = params.getString("collapsingToolBarImage");
24
-        } else {
23
+        if (hasBackgroundImage()) {
25
             result.imageUri = params.getString("collapsingToolBarImage");
24
             result.imageUri = params.getString("collapsingToolBarImage");
26
         }
25
         }
27
         result.scrimColor = getColor(params, "collapsingToolBarCollapsedColor", new StyleParams.Color(Color.WHITE));
26
         result.scrimColor = getColor(params, "collapsingToolBarCollapsedColor", new StyleParams.Color(Color.WHITE));
27
+        result.collapseBehaviour = getCollapseBehaviour();
28
         return result;
28
         return result;
29
     }
29
     }
30
 
30
 
31
-    private boolean hasLocalImageResource() {
31
+    private CollapseBehaviour getCollapseBehaviour() {
32
+        return shouldHideTitleBarOnScroll() ? CollapseBehaviour.TitleBarHideOnScroll : CollapseBehaviour.CollapseTopBar;
33
+    }
34
+
35
+    private boolean hasBackgroundImage() {
32
         return params.containsKey("collapsingToolBarImage");
36
         return params.containsKey("collapsingToolBarImage");
33
     }
37
     }
34
 
38
 
35
-    private boolean hasImageUrl() {
36
-        return params.containsKey("collapsingToolBarImageUrl");
39
+    private boolean shouldHideTitleBarOnScroll() {
40
+        return params.getBoolean("titleBarHideOnScroll", false);
37
     }
41
     }
38
 }
42
 }

+ 6
- 6
android/app/src/main/java/com/reactnativenavigation/params/parsers/Parser.java 查看文件

9
 import java.util.List;
9
 import java.util.List;
10
 
10
 
11
 public class Parser {
11
 public class Parser {
12
-    protected static boolean hasKey(Bundle bundle, String key) {
12
+    static boolean hasKey(Bundle bundle, String key) {
13
         return bundle.keySet().contains(key);
13
         return bundle.keySet().contains(key);
14
     }
14
     }
15
 
15
 
16
-    protected static void assertKeyExists(Bundle bundle, String key) {
16
+    static void assertKeyExists(Bundle bundle, String key) {
17
         if (!hasKey(bundle, key)) {
17
         if (!hasKey(bundle, key)) {
18
             throw new KeyDoesNotExistsException(key);
18
             throw new KeyDoesNotExistsException(key);
19
         }
19
         }
20
     }
20
     }
21
 
21
 
22
-    public static class KeyDoesNotExistsException extends RuntimeException {
23
-        public KeyDoesNotExistsException(String key) {
22
+    private static class KeyDoesNotExistsException extends RuntimeException {
23
+        KeyDoesNotExistsException(String key) {
24
             super(key);
24
             super(key);
25
         }
25
         }
26
     }
26
     }
27
 
27
 
28
-    protected interface ParseStrategy<T> {
28
+    interface ParseStrategy<T> {
29
         T parse(Bundle params);
29
         T parse(Bundle params);
30
     }
30
     }
31
 
31
 
32
-    protected <T> List<T> parseBundle(Bundle params, ParseStrategy<T> strategy) {
32
+    <T> List<T> parseBundle(Bundle params, ParseStrategy<T> strategy) {
33
         ArrayList<T> result = new ArrayList<>(Collections.nCopies(params.keySet().size(), (T) null));
33
         ArrayList<T> result = new ArrayList<>(Collections.nCopies(params.keySet().size(), (T) null));
34
         for (String key : params.keySet()) {
34
         for (String key : params.keySet()) {
35
             result.set(Integer.parseInt(key), strategy.parse(params.getBundle(key)));
35
             result.set(Integer.parseInt(key), strategy.parse(params.getBundle(key)));

+ 11
- 0
android/app/src/main/java/com/reactnativenavigation/params/parsers/StyleParamsParser.java 查看文件

29
         result.titleBarHidden = getBoolean("titleBarHidden", getDefaultTopBarHidden());
29
         result.titleBarHidden = getBoolean("titleBarHidden", getDefaultTopBarHidden());
30
         result.topBarTransparent = getBoolean("topBarTransparent", getDefaultTopBarHidden());
30
         result.topBarTransparent = getBoolean("topBarTransparent", getDefaultTopBarHidden());
31
         result.titleBarTitleColor = getColor("titleBarTitleColor", getDefaultTitleBarColor());
31
         result.titleBarTitleColor = getColor("titleBarTitleColor", getDefaultTitleBarColor());
32
+        result.topBarTranslucent = getBoolean("topBarTranslucent", getDefaultTopBarTranslucent());
33
+        result.titleBarHideOnScroll = getBoolean("titleBarHideOnScroll", getDefaultTitleBarHideOnScroll());
34
+
32
         result.titleBarSubtitleColor = getColor("titleBarSubtitleColor", getDefaultSubtitleBarColor());
35
         result.titleBarSubtitleColor = getColor("titleBarSubtitleColor", getDefaultSubtitleBarColor());
33
         result.titleBarButtonColor = getColor("titleBarButtonColor", getTitleBarButtonColor());
36
         result.titleBarButtonColor = getColor("titleBarButtonColor", getTitleBarButtonColor());
34
         result.titleBarDisabledButtonColor = getColor("titleBarDisabledButtonColor", getTitleBarDisabledButtonColor());
37
         result.titleBarDisabledButtonColor = getColor("titleBarDisabledButtonColor", getTitleBarDisabledButtonColor());
163
         return AppStyle.appStyle != null && AppStyle.appStyle.topBarTransparent;
166
         return AppStyle.appStyle != null && AppStyle.appStyle.topBarTransparent;
164
     }
167
     }
165
 
168
 
169
+    private boolean getDefaultTopBarTranslucent() {
170
+        return AppStyle.appStyle != null && AppStyle.appStyle.topBarTranslucent;
171
+    }
172
+
173
+    private boolean getDefaultTitleBarHideOnScroll() {
174
+        return AppStyle.appStyle != null && AppStyle.appStyle.titleBarHideOnScroll;
175
+    }
176
+
166
     private StyleParams.Color getDefaultTopBarColor() {
177
     private StyleParams.Color getDefaultTopBarColor() {
167
         return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.topBarColor;
178
         return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.topBarColor;
168
     }
179
     }

+ 5
- 3
android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarButtonParamsParser.java 查看文件

22
     public TitleBarButtonParams parseSingleButton(Bundle bundle) {
22
     public TitleBarButtonParams parseSingleButton(Bundle bundle) {
23
         TitleBarButtonParams result = new TitleBarButtonParams();
23
         TitleBarButtonParams result = new TitleBarButtonParams();
24
         result.label = bundle.getString("title");
24
         result.label = bundle.getString("title");
25
-        if (hasKey(bundle,"icon")) {
25
+        if (hasKey(bundle, "icon")) {
26
             result.icon = ImageLoader.loadImage(bundle.getString("icon"));
26
             result.icon = ImageLoader.loadImage(bundle.getString("icon"));
27
         }
27
         }
28
         result.color = getColor(bundle, "color", AppStyle.appStyle.titleBarButtonColor);
28
         result.color = getColor(bundle, "color", AppStyle.appStyle.titleBarButtonColor);
29
-        result.disabledColor = getColor(bundle, "disabledColor", AppStyle.appStyle.titleBarDisabledButtonColor);
29
+        result.disabledColor =
30
+                getColor(bundle, "disabledColor", AppStyle.appStyle.titleBarDisabledButtonColor);
30
         result.showAsAction = parseShowAsAction(bundle.getString("showAsAction"));
31
         result.showAsAction = parseShowAsAction(bundle.getString("showAsAction"));
31
         result.enabled = bundle.getBoolean("enabled", true);
32
         result.enabled = bundle.getBoolean("enabled", true);
33
+        result.hint = bundle.getString("hint", "");
32
         result.eventId = bundle.getString("id");
34
         result.eventId = bundle.getString("id");
33
         return result;
35
         return result;
34
     }
36
     }
35
 
37
 
36
-    protected BaseTitleBarButtonParams.ShowAsAction parseShowAsAction(String showAsAction) {
38
+    BaseTitleBarButtonParams.ShowAsAction parseShowAsAction(String showAsAction) {
37
         if (showAsAction == null) {
39
         if (showAsAction == null) {
38
             return BaseTitleBarButtonParams.ShowAsAction.IfRoom;
40
             return BaseTitleBarButtonParams.ShowAsAction.IfRoom;
39
         }
41
         }

+ 41
- 22
android/app/src/main/java/com/reactnativenavigation/screens/CollapsingSingleScreen.java 查看文件

3
 import android.support.v7.app.AppCompatActivity;
3
 import android.support.v7.app.AppCompatActivity;
4
 import android.widget.ScrollView;
4
 import android.widget.ScrollView;
5
 
5
 
6
+import com.reactnativenavigation.params.CollapsingTopBarParams;
6
 import com.reactnativenavigation.params.ScreenParams;
7
 import com.reactnativenavigation.params.ScreenParams;
7
-import com.reactnativenavigation.views.ContentView;
8
+import com.reactnativenavigation.views.CollapsingContentView;
8
 import com.reactnativenavigation.views.LeftButtonOnClickListener;
9
 import com.reactnativenavigation.views.LeftButtonOnClickListener;
10
+import com.reactnativenavigation.views.collapsingToolbar.CollapseAmount;
11
+import com.reactnativenavigation.views.collapsingToolbar.CollapseCalculator;
9
 import com.reactnativenavigation.views.collapsingToolbar.CollapsingContentViewMeasurer;
12
 import com.reactnativenavigation.views.collapsingToolbar.CollapsingContentViewMeasurer;
10
 import com.reactnativenavigation.views.collapsingToolbar.CollapsingTopBar;
13
 import com.reactnativenavigation.views.collapsingToolbar.CollapsingTopBar;
14
+import com.reactnativenavigation.views.collapsingToolbar.OnScrollListener;
11
 import com.reactnativenavigation.views.collapsingToolbar.OnScrollViewAddedListener;
15
 import com.reactnativenavigation.views.collapsingToolbar.OnScrollViewAddedListener;
12
 import com.reactnativenavigation.views.collapsingToolbar.ScrollListener;
16
 import com.reactnativenavigation.views.collapsingToolbar.ScrollListener;
13
 
17
 
17
         super(activity, screenParams, titleBarBarBackButtonListener);
21
         super(activity, screenParams, titleBarBarBackButtonListener);
18
     }
22
     }
19
 
23
 
24
+    @Override
25
+    public void destroy() {
26
+        super.destroy();
27
+        ((CollapsingContentView) contentView).destroy();
28
+    }
29
+
20
     @Override
30
     @Override
21
     protected void createTopBar() {
31
     protected void createTopBar() {
22
         final CollapsingTopBar topBar = new CollapsingTopBar(getContext(), styleParams.collapsingTopBarParams);
32
         final CollapsingTopBar topBar = new CollapsingTopBar(getContext(), styleParams.collapsingTopBarParams);
23
-        topBar.setScrollListener(new ScrollListener(topBar,
24
-                new ScrollListener.OnScrollListener() {
25
-                    @Override
26
-                    public void onScroll(float amount) {
27
-                        contentView.collapse(amount);
28
-                        topBar.collapse(amount);
29
-                    }
30
-                }
31
-        ));
33
+        topBar.setScrollListener(getScrollListener(topBar));
32
         this.topBar = topBar;
34
         this.topBar = topBar;
33
     }
35
     }
34
 
36
 
35
     @Override
37
     @Override
36
     protected void createContent() {
38
     protected void createContent() {
37
-        contentView = new ContentView(getContext(), screenParams.screenId, screenParams.navigationParams);
38
-        contentView.setViewMeasurer(new CollapsingContentViewMeasurer((CollapsingTopBar) topBar, this));
39
+        contentView = new CollapsingContentView(getContext(), screenParams.screenId, screenParams.navigationParams);
40
+        if (screenParams.styleParams.drawScreenBelowTopBar) {
41
+            contentView.setViewMeasurer(new CollapsingContentViewMeasurer((CollapsingTopBar) topBar, this));
42
+        }
39
         setupCollapseDetection((CollapsingTopBar) topBar);
43
         setupCollapseDetection((CollapsingTopBar) topBar);
40
         addView(contentView, createLayoutParams());
44
         addView(contentView, createLayoutParams());
41
     }
45
     }
42
 
46
 
43
     private void setupCollapseDetection(final CollapsingTopBar topBar) {
47
     private void setupCollapseDetection(final CollapsingTopBar topBar) {
44
-        contentView.setupCollapseDetection(new ScrollListener(topBar,
45
-                new ScrollListener.OnScrollListener() {
46
-                    @Override
47
-                    public void onScroll(float amount) {
48
-                        contentView.collapse(amount);
49
-                        topBar.collapse(amount);
50
-                    }
51
-                }
52
-        ));
53
-        contentView.setOnScrollViewAddedListener(new OnScrollViewAddedListener() {
48
+        ((CollapsingContentView) contentView).setupCollapseDetection(getScrollListener(topBar), new OnScrollViewAddedListener() {
54
             @Override
49
             @Override
55
             public void onScrollViewAdded(ScrollView scrollView) {
50
             public void onScrollViewAdded(ScrollView scrollView) {
56
                 topBar.onScrollViewAdded(scrollView);
51
                 topBar.onScrollViewAdded(scrollView);
57
             }
52
             }
58
         });
53
         });
59
     }
54
     }
55
+
56
+    private ScrollListener getScrollListener(final CollapsingTopBar topBar) {
57
+        return new ScrollListener(new CollapseCalculator(topBar, getCollapseBehaviour()),
58
+                new OnScrollListener() {
59
+                    @Override
60
+                    public void onScroll(CollapseAmount amount) {
61
+                        if (!screenParams.styleParams.titleBarHideOnScroll) {
62
+                            ((CollapsingContentView) contentView).collapse(amount);
63
+                        }
64
+                        topBar.collapse(amount);
65
+                    }
66
+
67
+                    @Override
68
+                    public void onFling(CollapseAmount amount) {
69
+                        topBar.collapse(amount);
70
+                    }
71
+                },
72
+                getCollapseBehaviour()
73
+        );
74
+    }
75
+
76
+    private CollapsingTopBarParams.CollapseBehaviour getCollapseBehaviour() {
77
+        return screenParams.styleParams.collapsingTopBarParams.collapseBehaviour;
78
+    }
60
 }
79
 }

+ 1
- 1
android/app/src/main/java/com/reactnativenavigation/screens/ContentViewPagerAdapter.java 查看文件

67
     private void sendTabSelectedEventToJs() {
67
     private void sendTabSelectedEventToJs() {
68
         WritableMap data = Arguments.createMap();
68
         WritableMap data = Arguments.createMap();
69
         String navigatorEventId = contentViews.get(currentPosition).getNavigatorEventId();
69
         String navigatorEventId = contentViews.get(currentPosition).getNavigatorEventId();
70
-        NavigationApplication.instance.sendNavigatorEvent("tabSelected", navigatorEventId, data);
70
+        NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("tabSelected", navigatorEventId, data);
71
     }
71
     }
72
 }
72
 }

+ 2
- 6
android/app/src/main/java/com/reactnativenavigation/screens/ScreenStack.java 查看文件

176
         stack.clear();
176
         stack.clear();
177
     }
177
     }
178
 
178
 
179
-    public int getStackSize() {
180
-        return stack.size();
181
-    }
182
-
183
     public boolean canPop() {
179
     public boolean canPop() {
184
-        return getStackSize() > 1 && !isPreviousScreenAttachedToWindow();
180
+        return stack.size() > 1 && !isPreviousScreenAttachedToWindow();
185
     }
181
     }
186
 
182
 
187
     private boolean isPreviousScreenAttachedToWindow() {
183
     private boolean isPreviousScreenAttachedToWindow() {
263
     public boolean handleBackPressInJs() {
259
     public boolean handleBackPressInJs() {
264
         ScreenParams currentScreen = stack.peek().screenParams;
260
         ScreenParams currentScreen = stack.peek().screenParams;
265
         if (currentScreen.overrideBackPressInJs) {
261
         if (currentScreen.overrideBackPressInJs) {
266
-            NavigationApplication.instance.sendNavigatorEvent("backPress", currentScreen.getNavigatorEventId());
262
+            NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("backPress", currentScreen.getNavigatorEventId());
267
             return true;
263
             return true;
268
         }
264
         }
269
         return false;
265
         return false;

+ 36
- 0
android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java 查看文件

5
 import android.graphics.PorterDuffColorFilter;
5
 import android.graphics.PorterDuffColorFilter;
6
 import android.graphics.drawable.Drawable;
6
 import android.graphics.drawable.Drawable;
7
 import android.os.Build;
7
 import android.os.Build;
8
+import android.support.annotation.Nullable;
8
 import android.util.DisplayMetrics;
9
 import android.util.DisplayMetrics;
9
 import android.view.View;
10
 import android.view.View;
11
+import android.view.ViewGroup;
10
 import android.view.ViewTreeObserver;
12
 import android.view.ViewTreeObserver;
11
 import android.view.WindowManager;
13
 import android.view.WindowManager;
12
 
14
 
79
             }
81
             }
80
         }
82
         }
81
     }
83
     }
84
+
85
+    /**
86
+     * Returns the first instance of clazz in root
87
+     */
88
+    @Nullable public static <T> T findChildByClass(ViewGroup root, Class clazz) {
89
+        for (int i = 0; i < root.getChildCount(); i++) {
90
+            View view = root.getChildAt(i);
91
+            if (clazz.isAssignableFrom(view.getClass())) {
92
+                return (T) view;
93
+            }
94
+
95
+            if (view instanceof ViewGroup) {
96
+                view = findChildByClass((ViewGroup) view, clazz);
97
+                if (view != null && clazz.isAssignableFrom(view.getClass())) {
98
+                    return (T) view;
99
+                }
100
+            }
101
+        }
102
+        return null;
103
+    }
104
+
105
+    public static void performOnChildren(ViewGroup root, PerformOnViewTask task) {
106
+        for (int i = 0; i < root.getChildCount(); i++) {
107
+            View child = root.getChildAt(i);
108
+            if (child instanceof ViewGroup) {
109
+                performOnChildren((ViewGroup) child, task);
110
+            }
111
+            task.runOnView(child);
112
+        }
113
+    }
114
+
115
+    public interface PerformOnViewTask {
116
+        void runOnView(View view);
117
+    }
82
 }
118
 }
83
 
119
 

+ 18
- 0
android/app/src/main/java/com/reactnativenavigation/views/ButtonFactory.java 查看文件

1
+package com.reactnativenavigation.views;
2
+
3
+import android.view.Menu;
4
+import android.view.View;
5
+
6
+import com.reactnativenavigation.params.TitleBarButtonParams;
7
+
8
+class ButtonFactory {
9
+
10
+    public static TitleBarButton create(Menu menu, View parent, TitleBarButtonParams params, String navigatorEventId) {
11
+        switch (params.eventId) {
12
+            case TitleBarSearchButton.BUTTON_ID:
13
+                return new TitleBarSearchButton(menu, parent, params, navigatorEventId);
14
+            default:
15
+                return new TitleBarButton(menu, parent, params, navigatorEventId);
16
+        }
17
+    }
18
+}

+ 79
- 0
android/app/src/main/java/com/reactnativenavigation/views/CollapsingContentView.java 查看文件

1
+package com.reactnativenavigation.views;
2
+
3
+import android.content.Context;
4
+import android.support.annotation.Nullable;
5
+import android.view.MotionEvent;
6
+import android.view.View;
7
+
8
+import com.reactnativenavigation.params.NavigationParams;
9
+import com.reactnativenavigation.views.collapsingToolbar.CollapseAmount;
10
+import com.reactnativenavigation.views.collapsingToolbar.CollapsingView;
11
+import com.reactnativenavigation.views.collapsingToolbar.OnScrollViewAddedListener;
12
+import com.reactnativenavigation.views.collapsingToolbar.ScrollListener;
13
+import com.reactnativenavigation.views.collapsingToolbar.ScrollViewDelegate;
14
+import com.reactnativenavigation.views.collapsingToolbar.ViewCollapser;
15
+import com.reactnativenavigation.views.utils.ScrollViewDetector;
16
+
17
+public class CollapsingContentView extends ContentView implements CollapsingView {
18
+
19
+    private @Nullable ScrollViewDelegate scrollViewDelegate;
20
+    private @Nullable ScrollViewDetector scrollViewDetector;
21
+    private final ViewCollapser viewCollapser;
22
+
23
+    public CollapsingContentView(Context context, String screenId, NavigationParams navigationParams) {
24
+        super(context, screenId, navigationParams);
25
+        viewCollapser = new ViewCollapser(this);
26
+    }
27
+
28
+    public void setupCollapseDetection(ScrollListener scrollListener, OnScrollViewAddedListener onScrollViewAddedListener) {
29
+        scrollViewDelegate = new ScrollViewDelegate(scrollListener);
30
+        scrollViewDetector = new ScrollViewDetector(this, onScrollViewAddedListener, scrollViewDelegate);
31
+    }
32
+
33
+    @Override
34
+    public boolean dispatchTouchEvent(MotionEvent ev) {
35
+        if (scrollViewDelegate != null) {
36
+            boolean consumed = scrollViewDelegate.didInterceptTouchEvent(ev);
37
+            if (consumed) {
38
+                return true;
39
+            }
40
+        }
41
+        return super.dispatchTouchEvent(ev);
42
+    }
43
+
44
+    @Override
45
+    public void onViewAdded(final View child) {
46
+        super.onViewAdded(child);
47
+        if (scrollViewDetector != null) {
48
+            scrollViewDetector.detectScrollViewAdded(child);
49
+        }
50
+    }
51
+
52
+    public void collapse(CollapseAmount amount) {
53
+        viewCollapser.collapse(amount);
54
+    }
55
+
56
+    public void destroy() {
57
+        if (scrollViewDelegate != null) {
58
+            scrollViewDelegate.destroy();
59
+        }
60
+        if (scrollViewDetector != null) {
61
+            scrollViewDetector.destroy();
62
+        }
63
+    }
64
+
65
+    @Override
66
+    public float getFinalCollapseValue() {
67
+        return 0;
68
+    }
69
+
70
+    @Override
71
+    public float getCurrentCollapseValue() {
72
+        return 0;
73
+    }
74
+
75
+    @Override
76
+    public View asView() {
77
+        return this;
78
+    }
79
+}

+ 1
- 42
android/app/src/main/java/com/reactnativenavigation/views/ContentView.java 查看文件

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
-import android.support.annotation.Nullable;
5
-import android.view.MotionEvent;
6
 import android.view.View;
4
 import android.view.View;
7
-import android.widget.ScrollView;
8
 
5
 
9
 import com.facebook.react.ReactRootView;
6
 import com.facebook.react.ReactRootView;
10
 import com.reactnativenavigation.NavigationApplication;
7
 import com.reactnativenavigation.NavigationApplication;
11
 import com.reactnativenavigation.params.NavigationParams;
8
 import com.reactnativenavigation.params.NavigationParams;
12
 import com.reactnativenavigation.screens.SingleScreen;
9
 import com.reactnativenavigation.screens.SingleScreen;
13
 import com.reactnativenavigation.utils.ViewUtils;
10
 import com.reactnativenavigation.utils.ViewUtils;
14
-import com.reactnativenavigation.views.collapsingToolbar.OnScrollViewAddedListener;
15
-import com.reactnativenavigation.views.collapsingToolbar.ScrollListener;
16
-import com.reactnativenavigation.views.collapsingToolbar.ScrollViewDelegate;
17
 import com.reactnativenavigation.views.utils.ViewMeasurer;
11
 import com.reactnativenavigation.views.utils.ViewMeasurer;
18
 
12
 
19
 public class ContentView extends ReactRootView {
13
 public class ContentView extends ReactRootView {
22
 
16
 
23
     boolean isContentVisible = false;
17
     boolean isContentVisible = false;
24
     private SingleScreen.OnDisplayListener onDisplayListener;
18
     private SingleScreen.OnDisplayListener onDisplayListener;
25
-    @Nullable private ScrollViewDelegate scrollViewDelegate;
26
-    private ViewMeasurer viewMeasurer;
27
-    private OnScrollViewAddedListener scrollViewAddedListener;
19
+    protected ViewMeasurer viewMeasurer;
28
 
20
 
29
     public void setOnDisplayListener(SingleScreen.OnDisplayListener onDisplayListener) {
21
     public void setOnDisplayListener(SingleScreen.OnDisplayListener onDisplayListener) {
30
         this.onDisplayListener = onDisplayListener;
22
         this.onDisplayListener = onDisplayListener;
31
     }
23
     }
32
 
24
 
33
-    public void setOnScrollViewAddedListener(OnScrollViewAddedListener scrollViewAddedListener) {
34
-        this.scrollViewAddedListener = scrollViewAddedListener;
35
-    }
36
-
37
     public ContentView(Context context, String screenId, NavigationParams navigationParams) {
25
     public ContentView(Context context, String screenId, NavigationParams navigationParams) {
38
         super(context);
26
         super(context);
39
         this.screenId = screenId;
27
         this.screenId = screenId;
42
         viewMeasurer = new ViewMeasurer();
30
         viewMeasurer = new ViewMeasurer();
43
     }
31
     }
44
 
32
 
45
-    public void setupCollapseDetection(ScrollListener scrollListener) {
46
-        scrollViewDelegate = new ScrollViewDelegate(scrollListener);
47
-    }
48
-
49
     public void setViewMeasurer(ViewMeasurer viewMeasurer) {
33
     public void setViewMeasurer(ViewMeasurer viewMeasurer) {
50
         this.viewMeasurer = viewMeasurer;
34
         this.viewMeasurer = viewMeasurer;
51
     }
35
     }
70
                 viewMeasurer.getMeasuredHeight(heightMeasureSpec));
54
                 viewMeasurer.getMeasuredHeight(heightMeasureSpec));
71
     }
55
     }
72
 
56
 
73
-    @Override
74
-    public boolean dispatchTouchEvent(MotionEvent ev) {
75
-        if (scrollViewDelegate != null) {
76
-            boolean consumed = scrollViewDelegate.didInterceptTouchEvent(ev);
77
-            if (consumed) {
78
-                return true;
79
-            }
80
-        }
81
-        return super.dispatchTouchEvent(ev);
82
-    }
83
-
84
     @Override
57
     @Override
85
     public void onViewAdded(final View child) {
58
     public void onViewAdded(final View child) {
86
         super.onViewAdded(child);
59
         super.onViewAdded(child);
87
         detectContentViewVisible(child);
60
         detectContentViewVisible(child);
88
-        if (child instanceof ScrollView) {
89
-            onScrollViewAdded((ScrollView) child);
90
-        }
91
-    }
92
-
93
-    private void onScrollViewAdded(ScrollView scrollView) {
94
-        if (scrollViewDelegate != null) {
95
-            scrollViewDelegate.onScrollViewAdded(scrollView);
96
-            scrollViewAddedListener.onScrollViewAdded(scrollView);
97
-        }
98
     }
61
     }
99
 
62
 
100
     private void detectContentViewVisible(View child) {
63
     private void detectContentViewVisible(View child) {
111
             });
74
             });
112
         }
75
         }
113
     }
76
     }
114
-
115
-    public void collapse(float collapse) {
116
-        setTranslationY(collapse);
117
-    }
118
 }
77
 }

+ 1
- 1
android/app/src/main/java/com/reactnativenavigation/views/ContextualMenu.java 查看文件

78
                 ((ViewManager) getParent()).removeView(ContextualMenu.this);
78
                 ((ViewManager) getParent()).removeView(ContextualMenu.this);
79
             }
79
             }
80
         });
80
         });
81
-        NavigationApplication.instance.sendNavigatorEvent("contextualMenuDismissed", navigatorEventId);
81
+        NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("contextualMenuDismissed", navigatorEventId);
82
     }
82
     }
83
 }
83
 }

+ 3
- 3
android/app/src/main/java/com/reactnativenavigation/views/FloatingActionButtonCoordinator.java 查看文件

94
                     fabAnimator.showExpended();
94
                     fabAnimator.showExpended();
95
                     showActions();
95
                     showActions();
96
                 }
96
                 }
97
-                NavigationApplication.instance.sendNavigatorEvent(params.collapsedId, params.navigatorEventId);
97
+                NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(params.collapsedId, params.navigatorEventId);
98
             }
98
             }
99
         });
99
         });
100
     }
100
     }
108
             @Override
108
             @Override
109
             public void onClick(View v) {
109
             public void onClick(View v) {
110
                 fabAnimator.collapse();
110
                 fabAnimator.collapse();
111
-                NavigationApplication.instance.sendNavigatorEvent(params.expendedId, params.navigatorEventId);
111
+                NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(params.expendedId, params.navigatorEventId);
112
             }
112
             }
113
         });
113
         });
114
     }
114
     }
153
         action.setOnClickListener(new View.OnClickListener() {
153
         action.setOnClickListener(new View.OnClickListener() {
154
             @Override
154
             @Override
155
             public void onClick(View v) {
155
             public void onClick(View v) {
156
-                NavigationApplication.instance.sendNavigatorEvent(actionParams.id, actionParams.navigatorEventId);
156
+                NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(actionParams.id, actionParams.navigatorEventId);
157
                 fabAnimator.collapse();
157
                 fabAnimator.collapse();
158
             }
158
             }
159
         });
159
         });

+ 9
- 9
android/app/src/main/java/com/reactnativenavigation/views/LeftButton.java 查看文件

9
 import com.reactnativenavigation.params.TitleBarButtonParams;
9
 import com.reactnativenavigation.params.TitleBarButtonParams;
10
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
10
 import com.reactnativenavigation.params.TitleBarLeftButtonParams;
11
 
11
 
12
-public class LeftButton extends MaterialMenuDrawable implements View.OnClickListener {
12
+class LeftButton extends MaterialMenuDrawable implements View.OnClickListener {
13
 
13
 
14
     private static int getColor(TitleBarButtonParams params) {
14
     private static int getColor(TitleBarButtonParams params) {
15
         return params != null && params.color.hasColor() ?
15
         return params != null && params.color.hasColor() ?
22
     private final String navigatorEventId;
22
     private final String navigatorEventId;
23
     private final boolean overrideBackPressInJs;
23
     private final boolean overrideBackPressInJs;
24
 
24
 
25
-    public LeftButton(Context context,
26
-                      TitleBarLeftButtonParams params,
27
-                      LeftButtonOnClickListener onClickListener,
28
-                      String navigatorEventId,
29
-                      boolean overrideBackPressInJs) {
25
+    LeftButton(Context context,
26
+               TitleBarLeftButtonParams params,
27
+               LeftButtonOnClickListener onClickListener,
28
+               String navigatorEventId,
29
+               boolean overrideBackPressInJs) {
30
         super(context, getColor(params), Stroke.THIN);
30
         super(context, getColor(params), Stroke.THIN);
31
         this.params = params;
31
         this.params = params;
32
         this.onClickListener = onClickListener;
32
         this.onClickListener = onClickListener;
35
         setInitialState();
35
         setInitialState();
36
     }
36
     }
37
 
37
 
38
-    public void setIconState(TitleBarLeftButtonParams params) {
38
+    void setIconState(TitleBarLeftButtonParams params) {
39
         this.params = params;
39
         this.params = params;
40
         if (params.color.hasColor()) {
40
         if (params.color.hasColor()) {
41
             setColor(params.color.getColor());
41
             setColor(params.color.getColor());
56
 
56
 
57
     private void handleBackButtonClick() {
57
     private void handleBackButtonClick() {
58
         if (overrideBackPressInJs) {
58
         if (overrideBackPressInJs) {
59
-            NavigationApplication.instance.sendNavigatorEvent("backPress", navigatorEventId);
59
+            NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("backPress", navigatorEventId);
60
         } else {
60
         } else {
61
             onClickListener.onTitleBarBackButtonClick();
61
             onClickListener.onTitleBarBackButtonClick();
62
         }
62
         }
79
     }
79
     }
80
 
80
 
81
     private void sendClickEvent() {
81
     private void sendClickEvent() {
82
-        NavigationApplication.instance.sendNavigatorEvent(params.eventId, navigatorEventId);
82
+        NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(params.eventId, navigatorEventId);
83
     }
83
     }
84
 }
84
 }

+ 5
- 5
android/app/src/main/java/com/reactnativenavigation/views/Snakbar.java 查看文件

6
 import com.reactnativenavigation.NavigationApplication;
6
 import com.reactnativenavigation.NavigationApplication;
7
 import com.reactnativenavigation.params.SnackbarParams;
7
 import com.reactnativenavigation.params.SnackbarParams;
8
 
8
 
9
-public class Snakbar {
9
+class Snakbar {
10
     private final OnDismissListener parent;
10
     private final OnDismissListener parent;
11
     private final String navigatorEventId;
11
     private final String navigatorEventId;
12
     private final SnackbarParams params;
12
     private final SnackbarParams params;
13
     private Snackbar snackbar;
13
     private Snackbar snackbar;
14
 
14
 
15
-    public interface OnDismissListener {
15
+    interface OnDismissListener {
16
         void onDismiss(Snakbar snakbar);
16
         void onDismiss(Snakbar snakbar);
17
     }
17
     }
18
 
18
 
20
         snackbar.show();
20
         snackbar.show();
21
     }
21
     }
22
 
22
 
23
-    public void dismiss() {
23
+    void dismiss() {
24
         snackbar.dismiss();
24
         snackbar.dismiss();
25
     }
25
     }
26
 
26
 
28
         return snackbar.getView();
28
         return snackbar.getView();
29
     }
29
     }
30
 
30
 
31
-    public Snakbar(OnDismissListener parent, String navigatorEventId, SnackbarParams params) {
31
+    Snakbar(OnDismissListener parent, String navigatorEventId, SnackbarParams params) {
32
         this.parent = parent;
32
         this.parent = parent;
33
         this.navigatorEventId = navigatorEventId;
33
         this.navigatorEventId = navigatorEventId;
34
         this.params = params;
34
         this.params = params;
47
             snackbar.setAction(params.buttonText, new View.OnClickListener() {
47
             snackbar.setAction(params.buttonText, new View.OnClickListener() {
48
                 @Override
48
                 @Override
49
                 public void onClick(View v) {
49
                 public void onClick(View v) {
50
-                    NavigationApplication.instance.sendNavigatorEvent(params.eventId, navigatorEventId);
50
+                    NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(params.eventId, navigatorEventId);
51
                 }
51
                 }
52
             });
52
             });
53
         }
53
         }

+ 8
- 1
android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java 查看文件

62
         setTitleTextColor(params);
62
         setTitleTextColor(params);
63
         setSubtitleTextColor(params);
63
         setSubtitleTextColor(params);
64
         colorOverflowButton(params);
64
         colorOverflowButton(params);
65
+        setTranslucent(params);
65
     }
66
     }
66
 
67
 
67
     private void colorOverflowButton(StyleParams params) {
68
     private void colorOverflowButton(StyleParams params) {
71
         }
72
         }
72
     }
73
     }
73
 
74
 
75
+    private void setTranslucent(StyleParams params) {
76
+        if (params.topBarTranslucent) {
77
+            setBackground(new TranslucentTitleBarBackground());
78
+        }
79
+    }
80
+
74
     private boolean shouldColorOverflowButton(StyleParams params, Drawable overflowIcon) {
81
     private boolean shouldColorOverflowButton(StyleParams params, Drawable overflowIcon) {
75
         return overflowIcon != null && params.titleBarButtonColor.hasColor();
82
         return overflowIcon != null && params.titleBarButtonColor.hasColor();
76
     }
83
     }
89
 
96
 
90
     private void addButtonsToTitleBar(List<TitleBarButtonParams> rightButtons, String navigatorEventId, Menu menu) {
97
     private void addButtonsToTitleBar(List<TitleBarButtonParams> rightButtons, String navigatorEventId, Menu menu) {
91
         for (int i = 0; i < rightButtons.size(); i++) {
98
         for (int i = 0; i < rightButtons.size(); i++) {
92
-            final TitleBarButton button = new TitleBarButton(menu, this, rightButtons.get(i), navigatorEventId);
99
+            final TitleBarButton button = ButtonFactory.create(menu, this, rightButtons.get(i), navigatorEventId);
93
             addButtonInReverseOrder(rightButtons, i, button);
100
             addButtonInReverseOrder(rightButtons, i, button);
94
         }
101
         }
95
     }
102
     }

+ 4
- 4
android/app/src/main/java/com/reactnativenavigation/views/TitleBarButton.java 查看文件

15
 
15
 
16
 class TitleBarButton implements MenuItem.OnMenuItemClickListener {
16
 class TitleBarButton implements MenuItem.OnMenuItemClickListener {
17
 
17
 
18
-    private final Menu menu;
19
-    private final View parent;
18
+    protected final Menu menu;
19
+    protected final View parent;
20
     protected TitleBarButtonParams buttonParams;
20
     protected TitleBarButtonParams buttonParams;
21
-    @Nullable private String navigatorEventId;
21
+    @Nullable protected String navigatorEventId;
22
 
22
 
23
     TitleBarButton(Menu menu, View parent, TitleBarButtonParams buttonParams, @Nullable String navigatorEventId) {
23
     TitleBarButton(Menu menu, View parent, TitleBarButtonParams buttonParams, @Nullable String navigatorEventId) {
24
         this.menu = menu;
24
         this.menu = menu;
93
 
93
 
94
     @Override
94
     @Override
95
     public boolean onMenuItemClick(MenuItem item) {
95
     public boolean onMenuItemClick(MenuItem item) {
96
-        NavigationApplication.instance.sendNavigatorEvent(buttonParams.eventId, navigatorEventId);
96
+        NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(buttonParams.eventId, navigatorEventId);
97
         return true;
97
         return true;
98
     }
98
     }
99
 }
99
 }

+ 156
- 0
android/app/src/main/java/com/reactnativenavigation/views/TitleBarSearchButton.java 查看文件

1
+package com.reactnativenavigation.views;
2
+
3
+import android.app.Activity;
4
+import android.graphics.drawable.Drawable;
5
+import android.support.annotation.Nullable;
6
+import android.support.v4.view.MenuItemCompat;
7
+import android.support.v7.widget.SearchView;
8
+import android.support.v7.widget.Toolbar;
9
+import android.view.Menu;
10
+import android.view.MenuItem;
11
+import android.view.View;
12
+import android.view.ViewGroup;
13
+import android.widget.EditText;
14
+import android.widget.ImageButton;
15
+import android.widget.ImageView;
16
+
17
+import com.facebook.react.bridge.Arguments;
18
+import com.facebook.react.bridge.WritableMap;
19
+import com.reactnativenavigation.NavigationApplication;
20
+import com.reactnativenavigation.R;
21
+import com.reactnativenavigation.params.TitleBarButtonParams;
22
+import com.reactnativenavigation.utils.ReflectionUtils;
23
+import com.reactnativenavigation.utils.ViewUtils;
24
+
25
+class TitleBarSearchButton extends TitleBarButton implements SearchView.OnQueryTextListener, View.OnFocusChangeListener, View.OnClickListener {
26
+    static final String BUTTON_ID = "searchView";
27
+    private SearchView searchView;
28
+
29
+    TitleBarSearchButton(Menu menu, View parent, TitleBarButtonParams buttonParams, @Nullable String navigatorEventId) {
30
+        super(menu, parent, buttonParams, navigatorEventId);
31
+    }
32
+
33
+    MenuItem addToMenu(int index) {
34
+        ((Activity) parent.getContext()).getMenuInflater().inflate(R.menu.search_item, menu);
35
+        MenuItem item = menu.findItem(R.id.toolbar_action_search);
36
+        item.setOnMenuItemClickListener(this);
37
+        if (buttonParams.icon != null) {
38
+            item.setIcon(buttonParams.icon);
39
+        }
40
+        searchView = (SearchView) MenuItemCompat.getActionView(item);
41
+        searchView.setQueryHint(buttonParams.hint);
42
+        searchView.setOnQueryTextFocusChangeListener(this);
43
+        searchView.setOnQueryTextListener(this);
44
+        searchView.setOnSearchClickListener(this);
45
+        setColor();
46
+        return item;
47
+    }
48
+
49
+    private void setColor() {
50
+        EditText searchEditText = ViewUtils.findChildByClass(searchView, EditText.class);
51
+        if (searchEditText != null) {
52
+            if (buttonParams.color.hasColor()) {
53
+                searchEditText.setTextColor(buttonParams.color.getColor());
54
+                searchEditText.setHintTextColor(buttonParams.color.getColor());
55
+            }
56
+            colorCloseButton(searchEditText);
57
+            setImagePlateColor();
58
+        }
59
+    }
60
+
61
+    private void colorCloseButton(EditText searchEditText) {
62
+        ViewUtils.performOnChildren((ViewGroup) searchEditText.getParent(), new ViewUtils.PerformOnViewTask() {
63
+            @Override
64
+            public void runOnView(View view) {
65
+                if (view instanceof ImageView) {
66
+                    if (buttonParams.color.hasColor()) {
67
+                        ((ImageView) view).setColorFilter(buttonParams.color.getColor());
68
+                    }
69
+                }
70
+            }
71
+        });
72
+    }
73
+
74
+    private void setImagePlateColor() {
75
+        if (buttonParams.color.hasColor()) {
76
+            Object mSearchPlate = ReflectionUtils.getDeclaredField(searchView, "mSearchPlate");
77
+            if (mSearchPlate != null) {
78
+                Drawable background = ((View) mSearchPlate).getBackground();
79
+                if (background != null) {
80
+                    ViewUtils.tintDrawable(background, buttonParams.color.getColor(), true);
81
+                }
82
+            }
83
+        }
84
+    }
85
+
86
+    @Override
87
+    public boolean onMenuItemClick(MenuItem item) {
88
+        setupBackButtonAfterSearchViewIsExpended();
89
+        return false;
90
+    }
91
+
92
+    private void setupBackButtonAfterSearchViewIsExpended() {
93
+        ViewUtils.runOnPreDraw(searchView, new Runnable() {
94
+            @Override
95
+            public void run() {
96
+                Object backButton = ViewUtils.findChildByClass((ViewGroup) searchView.getParent(), ImageButton.class);
97
+                if (backButton != null) {
98
+                    setBackButtonClickListener((View) backButton);
99
+                    colorBackButton((ImageView) backButton);
100
+                }
101
+            }
102
+
103
+            private void colorBackButton(ImageView backButton) {
104
+                if (buttonParams.color.hasColor()) {
105
+                    ViewUtils.tintDrawable(backButton.getDrawable(), buttonParams.color.getColor(), true);
106
+                }
107
+            }
108
+
109
+            private void setBackButtonClickListener(View backButton) {
110
+                backButton.setOnClickListener(new View.OnClickListener() {
111
+                    @Override
112
+                    public void onClick(View v) {
113
+                        ((Toolbar) searchView.getParent()).collapseActionView();
114
+                        sendEvent("searchViewHidden");
115
+                    }
116
+                });
117
+            }
118
+        });
119
+    }
120
+
121
+    @Override
122
+    public boolean onQueryTextSubmit(String query) {
123
+        WritableMap arguments = Arguments.createMap();
124
+        arguments.putString("query", query);
125
+        sendEvent("searchQuerySubmit", arguments);
126
+        return false;
127
+    }
128
+
129
+    @Override
130
+    public boolean onQueryTextChange(String newText) {
131
+        WritableMap arguments = Arguments.createMap();
132
+        arguments.putString("query", newText);
133
+        sendEvent("searchQueryChange", arguments);
134
+        return false;
135
+    }
136
+
137
+    @Override
138
+    public void onFocusChange(View v, boolean hasFocus) {
139
+        WritableMap arguments = Arguments.createMap();
140
+        arguments.putBoolean("hasFocus", hasFocus);
141
+        sendEvent("searchFocusChange", arguments);
142
+    }
143
+
144
+    @Override
145
+    public void onClick(View v) {
146
+        sendEvent("searchViewShown");
147
+    }
148
+
149
+    private void sendEvent(String eventId, WritableMap arguments) {
150
+        NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(eventId, navigatorEventId, arguments);
151
+    }
152
+
153
+    private void sendEvent(String eventId) {
154
+        NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(eventId, navigatorEventId);
155
+    }
156
+}

+ 0
- 1
android/app/src/main/java/com/reactnativenavigation/views/TopBar.java 查看文件

78
     private void setTransparent() {
78
     private void setTransparent() {
79
         setBackgroundColor(Color.TRANSPARENT);
79
         setBackgroundColor(Color.TRANSPARENT);
80
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
80
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
81
-            setElevation(0);
82
             setOutlineProvider(null);
81
             setOutlineProvider(null);
83
         }
82
         }
84
     }
83
     }

+ 36
- 0
android/app/src/main/java/com/reactnativenavigation/views/TranslucentTitleBarBackground.java 查看文件

1
+package com.reactnativenavigation.views;
2
+
3
+import android.graphics.Color;
4
+import android.graphics.LinearGradient;
5
+import android.graphics.Shader;
6
+import android.graphics.drawable.PaintDrawable;
7
+import android.graphics.drawable.ShapeDrawable;
8
+import android.graphics.drawable.shapes.RectShape;
9
+
10
+class TranslucentTitleBarBackground extends PaintDrawable {
11
+
12
+    TranslucentTitleBarBackground() {
13
+        setShape(new RectShape());
14
+        createShader();
15
+    }
16
+
17
+    private void createShader() {
18
+        ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
19
+            @Override
20
+            public Shader resize(int width, int height) {
21
+                double angleInRadians = Math.toRadians(90);
22
+
23
+                int x1 = (int) (Math.cos(angleInRadians) * width);
24
+                int y1 = (int) (Math.sin(angleInRadians) * height);
25
+                int[] colors = new int[]{Color.argb(90, 0, 0, 0), Color.argb(15, 0, 0, 0), Color.TRANSPARENT};
26
+                float[] positions = {0, 0.78f, 1};
27
+                LinearGradient lg = new LinearGradient(0, 0, x1, y1,
28
+                        colors,
29
+                        positions,
30
+                        Shader.TileMode.REPEAT);
31
+                return lg;
32
+            }
33
+        };
34
+        setShaderFactory(sf);
35
+    }
36
+}

+ 17
- 5
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseAmount.java 查看文件

1
 package com.reactnativenavigation.views.collapsingToolbar;
1
 package com.reactnativenavigation.views.collapsingToolbar;
2
 
2
 
3
 public class CollapseAmount {
3
 public class CollapseAmount {
4
-    public final static CollapseAmount None = new CollapseAmount();
4
+    final static CollapseAmount None = new CollapseAmount();
5
+
6
+    private CollapseAmount() {}
7
+
5
     private Float amount;
8
     private Float amount;
9
+    private CollapseCalculator.Direction direction;
6
 
10
 
7
-    public CollapseAmount(float amount) {
11
+    CollapseAmount(float amount) {
8
         this.amount = amount;
12
         this.amount = amount;
9
     }
13
     }
10
 
14
 
11
-    private CollapseAmount() {
15
+    CollapseAmount(CollapseCalculator.Direction direction) {
16
+        this.direction = direction;
17
+    }
18
+
19
+    boolean canCollapse() {
20
+        return amount != null || this != None;
21
+    }
12
 
22
 
23
+    boolean collapseToTop() {
24
+        return direction == CollapseCalculator.Direction.Up;
13
     }
25
     }
14
 
26
 
15
-    public boolean canCollapse() {
16
-        return amount != null;
27
+    boolean collapseToBottom() {
28
+        return direction == CollapseCalculator.Direction.Down;
17
     }
29
     }
18
 
30
 
19
     public float get() {
31
     public float get() {

+ 99
- 20
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseCalculator.java 查看文件

2
 
2
 
3
 import android.support.annotation.NonNull;
3
 import android.support.annotation.NonNull;
4
 import android.support.annotation.Nullable;
4
 import android.support.annotation.Nullable;
5
+import android.view.GestureDetector;
5
 import android.view.MotionEvent;
6
 import android.view.MotionEvent;
6
 import android.widget.ScrollView;
7
 import android.widget.ScrollView;
7
 
8
 
8
-class CollapseCalculator {
9
+import com.reactnativenavigation.NavigationApplication;
10
+import com.reactnativenavigation.params.CollapsingTopBarParams.CollapseBehaviour;
11
+
12
+import static com.reactnativenavigation.params.CollapsingTopBarParams.CollapseBehaviour.TitleBarHideOnScroll;
13
+
14
+public class CollapseCalculator {
15
+    enum Direction {
16
+        Up, Down, None
17
+    }
18
+
9
     private float collapse;
19
     private float collapse;
10
     private MotionEvent previousTouchEvent;
20
     private MotionEvent previousTouchEvent;
11
     private float touchDownY = -1;
21
     private float touchDownY = -1;
15
     private boolean canCollapse = true;
25
     private boolean canCollapse = true;
16
     private boolean canExpend = false;
26
     private boolean canExpend = false;
17
     private CollapsingView view;
27
     private CollapsingView view;
28
+    private CollapseBehaviour collapseBehaviour;
18
     protected ScrollView scrollView;
29
     protected ScrollView scrollView;
30
+    private GestureDetector flingDetector;
31
+    private OnFlingListener flingListener;
32
+    private int scrollY = 0;
33
+    private int totalCollapse = 0;
19
 
34
 
20
-    CollapseCalculator(final CollapsingView collapsingView) {
35
+    public CollapseCalculator(final CollapsingView collapsingView, CollapseBehaviour collapseBehaviour) {
21
         this.view = collapsingView;
36
         this.view = collapsingView;
37
+        this.collapseBehaviour = collapseBehaviour;
38
+        setFlingDetector(collapseBehaviour);
39
+    }
40
+
41
+    private void setFlingDetector(CollapseBehaviour collapseBehaviour) {
42
+        if (collapseBehaviour == TitleBarHideOnScroll) {
43
+            flingDetector =
44
+                    new GestureDetector(NavigationApplication.instance, new GestureDetector.SimpleOnGestureListener() {
45
+                        @Override
46
+                        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
47
+                            final Direction direction = getScrollDirection(e1, e2);
48
+                            if (canCollapse(direction) && totalCollapse != 0) {
49
+                                flingListener.onFling(new CollapseAmount(direction));
50
+                                return true;
51
+                            }
52
+                            return false;
53
+                        }
54
+
55
+                        private Direction getScrollDirection(MotionEvent e1, MotionEvent e2) {
56
+                            if (e1.getRawY() == e2.getRawY()) {
57
+                                return Direction.None;
58
+                            }
59
+                            return e1.getRawY() - e2.getRawY() > 0 ? Direction.Up : Direction.Down;
60
+                        }
61
+                    });
62
+        }
22
     }
63
     }
23
 
64
 
24
     void setScrollView(ScrollView scrollView) {
65
     void setScrollView(ScrollView scrollView) {
25
         this.scrollView = scrollView;
66
         this.scrollView = scrollView;
26
     }
67
     }
27
 
68
 
69
+    void setFlingListener(OnFlingListener flingListener) {
70
+        this.flingListener = flingListener;
71
+    }
72
+
28
     @NonNull
73
     @NonNull
29
     CollapseAmount calculate(MotionEvent event) {
74
     CollapseAmount calculate(MotionEvent event) {
30
         updateInitialTouchY(event);
75
         updateInitialTouchY(event);
76
+        CollapseAmount touchUpCollapse = shouldCollapseOnTouchUp(event);
77
+        if (touchUpCollapse != CollapseAmount.None) {
78
+            previousTouchEvent = MotionEvent.obtain(event);
79
+            return touchUpCollapse;
80
+        }
81
+
31
         if (!isMoveEvent(event)) {
82
         if (!isMoveEvent(event)) {
83
+            previousTouchEvent = MotionEvent.obtain(event);
32
             return CollapseAmount.None;
84
             return CollapseAmount.None;
33
         }
85
         }
34
 
86
 
35
-        if (shouldCollapse(event)) {
87
+        final Direction direction = calculateScrollDirection(event.getRawY());
88
+        if (shouldCollapseAfterMoveEvent(direction)) {
36
             return calculateCollapse(event);
89
             return calculateCollapse(event);
37
         } else {
90
         } else {
38
             previousCollapseY = -1;
91
             previousCollapseY = -1;
41
         }
94
         }
42
     }
95
     }
43
 
96
 
44
-    private boolean shouldCollapse(MotionEvent event) {
97
+    private CollapseAmount shouldCollapseOnTouchUp(MotionEvent event) {
98
+        if (collapseBehaviour == TitleBarHideOnScroll && !flingDetector.onTouchEvent(event) && isTouchUp(event)) {
99
+            final float visibilityPercentage = view.getCurrentCollapseValue() / view.getFinalCollapseValue();
100
+            Direction direction = visibilityPercentage >= 0.5f ? Direction.Up : Direction.Down;
101
+            if (canCollapse(direction) && totalCollapse != 0) {
102
+                return new CollapseAmount(direction);
103
+            }
104
+        }
105
+        return CollapseAmount.None;
106
+    }
107
+
108
+    private boolean shouldCollapseAfterMoveEvent(Direction direction) {
109
+        if (collapseBehaviour == CollapseBehaviour.TitleBarHideOnScroll && !isScrolling()) {
110
+            return false;
111
+        }
112
+        return canCollapse(direction);
113
+    }
114
+
115
+    private boolean canCollapse(Direction direction) {
45
         checkCollapseLimits();
116
         checkCollapseLimits();
46
-        ScrollDirection.Direction direction = getScrollDirection(event.getRawY());
47
-        return isNotCollapsedOrExpended() ||
48
-                (canCollapse && isExpendedAndScrollingUp(direction)) ||
49
-                (canExpend && isCollapsedAndScrollingDown(direction));
117
+        return (isNotCollapsedOrExpended() ||
118
+               (canCollapse && isExpendedAndScrollingUp(direction)) ||
119
+               (canExpend && isCollapsedAndScrollingDown(direction)));
120
+    }
121
+
122
+    private boolean isScrolling() {
123
+        final int currentScrollY = scrollView.getScrollY();
124
+        final boolean isScrolling = currentScrollY != scrollY;
125
+        scrollY = currentScrollY;
126
+        return isScrolling;
50
     }
127
     }
51
 
128
 
52
-    private ScrollDirection.Direction getScrollDirection(float y) {
129
+    private Direction calculateScrollDirection(float y) {
53
         if (y == (previousCollapseY == -1 ? touchDownY : previousCollapseY)) {
130
         if (y == (previousCollapseY == -1 ? touchDownY : previousCollapseY)) {
54
-            return ScrollDirection.Direction.None;
131
+            return Direction.None;
55
         }
132
         }
56
         if (previousTouchEvent == null) {
133
         if (previousTouchEvent == null) {
57
-            return ScrollDirection.Direction.None;
134
+            return Direction.None;
58
         }
135
         }
59
         return y < previousTouchEvent.getRawY() ?
136
         return y < previousTouchEvent.getRawY() ?
60
-                ScrollDirection.Direction.Up :
61
-                ScrollDirection.Direction.Down;
137
+                Direction.Up :
138
+                Direction.Down;
62
     }
139
     }
63
 
140
 
64
     private void checkCollapseLimits() {
141
     private void checkCollapseLimits() {
78
     private boolean calculateCanExpend(float currentTopBarTranslation, float finalExpendedTranslation, float finalCollapsedTranslation) {
155
     private boolean calculateCanExpend(float currentTopBarTranslation, float finalExpendedTranslation, float finalCollapsedTranslation) {
79
         return currentTopBarTranslation >= finalCollapsedTranslation &&
156
         return currentTopBarTranslation >= finalCollapsedTranslation &&
80
                currentTopBarTranslation < finalExpendedTranslation &&
157
                currentTopBarTranslation < finalExpendedTranslation &&
81
-               scrollView.getScrollY() == 0;
158
+               (scrollView.getScrollY() == 0 || collapseBehaviour == CollapseBehaviour.TitleBarHideOnScroll);
82
     }
159
     }
83
 
160
 
84
-    private boolean isCollapsedAndScrollingDown(ScrollDirection.Direction direction) {
85
-        return isCollapsed && direction == ScrollDirection.Direction.Down;
161
+    private boolean isCollapsedAndScrollingDown(Direction direction) {
162
+        return isCollapsed && direction == Direction.Down;
86
     }
163
     }
87
 
164
 
88
-    private boolean isExpendedAndScrollingUp(ScrollDirection.Direction direction) {
89
-        return isExpended && direction == ScrollDirection.Direction.Up;
165
+    private boolean isExpendedAndScrollingUp(Direction direction) {
166
+        return isExpended && direction == Direction.Up;
90
     }
167
     }
91
 
168
 
92
-    private  boolean isNotCollapsedOrExpended() {
169
+    private boolean isNotCollapsedOrExpended() {
93
         return canExpend && canCollapse;
170
         return canExpend && canCollapse;
94
     }
171
     }
95
 
172
 
107
             previousCollapseY = y;
184
             previousCollapseY = y;
108
         }
185
         }
109
         collapse = calculateCollapse(y);
186
         collapse = calculateCollapse(y);
187
+        totalCollapse += collapse;
110
         previousCollapseY = y;
188
         previousCollapseY = y;
111
         previousTouchEvent = MotionEvent.obtain(event);
189
         previousTouchEvent = MotionEvent.obtain(event);
112
         return new CollapseAmount(collapse);
190
         return new CollapseAmount(collapse);
146
     }
224
     }
147
 
225
 
148
     private void saveInitialTouchY(MotionEvent event) {
226
     private void saveInitialTouchY(MotionEvent event) {
227
+        totalCollapse = 0;
149
         touchDownY = event.getRawY();
228
         touchDownY = event.getRawY();
229
+        scrollY = scrollView.getScrollY();
150
         previousCollapseY = touchDownY;
230
         previousCollapseY = touchDownY;
151
     }
231
     }
152
 
232
 
153
     private void clearInitialTouchY() {
233
     private void clearInitialTouchY() {
154
-        touchDownY = -1;
155
         previousCollapseY = -1;
234
         previousCollapseY = -1;
156
         collapse = 0;
235
         collapse = 0;
157
     }
236
     }

+ 38
- 14
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBar.java 查看文件

13
     private CollapsingTopBarBackground collapsingTopBarBackground;
13
     private CollapsingTopBarBackground collapsingTopBarBackground;
14
     private ScrollListener scrollListener;
14
     private ScrollListener scrollListener;
15
     private float finalCollapsedTranslation;
15
     private float finalCollapsedTranslation;
16
+    private CollapsingTopBarParams params;
17
+    private final ViewCollapser viewCollapser;
16
 
18
 
17
-    public CollapsingTopBar(Context context, CollapsingTopBarParams params) {
19
+    public CollapsingTopBar(Context context, final CollapsingTopBarParams params) {
18
         super(context);
20
         super(context);
21
+        this.params = params;
19
         createCollapsingTopBar(params);
22
         createCollapsingTopBar(params);
23
+        calculateFinalCollapsedTranslation(params);
24
+        viewCollapser = new ViewCollapser(this);
25
+    }
26
+
27
+    private void calculateFinalCollapsedTranslation(final CollapsingTopBarParams params) {
20
         ViewUtils.runOnPreDraw(this, new Runnable() {
28
         ViewUtils.runOnPreDraw(this, new Runnable() {
21
             @Override
29
             @Override
22
             public void run() {
30
             public void run() {
23
-                finalCollapsedTranslation = getCollapsingTopBarBackground().getCollapsedTopBarHeight() - getHeight();
31
+                if (params.hasBackgroundImage()) {
32
+                    finalCollapsedTranslation =
33
+                            getCollapsingTopBarBackground().getCollapsedTopBarHeight() - getHeight();
34
+                } else {
35
+                    finalCollapsedTranslation = -titleBar.getHeight();
36
+                }
24
             }
37
             }
25
         });
38
         });
26
-
27
     }
39
     }
28
 
40
 
29
     public void setScrollListener(ScrollListener scrollListener) {
41
     public void setScrollListener(ScrollListener scrollListener) {
31
     }
43
     }
32
 
44
 
33
     private void createCollapsingTopBar(CollapsingTopBarParams params) {
45
     private void createCollapsingTopBar(CollapsingTopBarParams params) {
34
-        collapsingTopBarBackground = new CollapsingTopBarBackground(getContext(), params);
35
-        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, (int) CollapsingTopBarBackground.MAX_HEIGHT);
36
-        titleBarAndContextualMenuContainer.addView(collapsingTopBarBackground, lp);
46
+        if (params.hasBackgroundImage()) {
47
+            collapsingTopBarBackground = new CollapsingTopBarBackground(getContext(), params);
48
+            LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, (int) CollapsingTopBarBackground.MAX_HEIGHT);
49
+            titleBarAndContextualMenuContainer.addView(collapsingTopBarBackground, lp);
50
+        }
37
     }
51
     }
38
 
52
 
39
     @Override
53
     @Override
40
     protected TitleBar createTitleBar() {
54
     protected TitleBar createTitleBar() {
41
-        return new CollapsingTitleBar(getContext(),
42
-                collapsingTopBarBackground.getCollapsedTopBarHeight(),
43
-                scrollListener);
55
+        if (params.hasBackgroundImage()) {
56
+            return new CollapsingTitleBar(getContext(),
57
+                    collapsingTopBarBackground.getCollapsedTopBarHeight(),
58
+                    scrollListener);
59
+        } else {
60
+            return super.createTitleBar();
61
+        }
44
     }
62
     }
45
 
63
 
46
     public CollapsingTopBarBackground getCollapsingTopBarBackground() {
64
     public CollapsingTopBarBackground getCollapsingTopBarBackground() {
47
         return collapsingTopBarBackground;
65
         return collapsingTopBarBackground;
48
     }
66
     }
49
 
67
 
50
-    public void collapse(float collapse) {
51
-        setTranslationY(collapse);
52
-        ((CollapsingTitleBar) titleBar).collapse(collapse);
53
-        collapsingTopBarBackground.collapse(collapse);
68
+    public void collapse(CollapseAmount amount) {
69
+        viewCollapser.collapse(amount);
70
+        if (titleBar instanceof CollapsingTitleBar) {
71
+            ((CollapsingTitleBar) titleBar).collapse(amount.get());
72
+        }
73
+        if (collapsingTopBarBackground != null) {
74
+            collapsingTopBarBackground.collapse(amount.get());
75
+        }
54
     }
76
     }
55
 
77
 
56
     public void onScrollViewAdded(ScrollView scrollView) {
78
     public void onScrollViewAdded(ScrollView scrollView) {
63
     }
85
     }
64
 
86
 
65
     public int getCollapsedHeight() {
87
     public int getCollapsedHeight() {
66
-        return collapsingTopBarBackground.getCollapsedTopBarHeight();
88
+        return params.hasBackgroundImage() ?
89
+                collapsingTopBarBackground.getCollapsedTopBarHeight() :
90
+                titleBar.getHeight();
67
     }
91
     }
68
 
92
 
69
     @Override
93
     @Override

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnFlingListener.java 查看文件

1
+package com.reactnativenavigation.views.collapsingToolbar;
2
+
3
+interface OnFlingListener {
4
+    void onFling(CollapseAmount amount);
5
+}

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnScrollListener.java 查看文件

1
+package com.reactnativenavigation.views.collapsingToolbar;
2
+
3
+public interface  OnScrollListener extends OnFlingListener {
4
+    void onScroll(CollapseAmount amount);
5
+}

+ 0
- 50
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollDirection.java 查看文件

1
-package com.reactnativenavigation.views.collapsingToolbar;
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
-}

+ 13
- 13
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollListener.java 查看文件

3
 import android.view.MotionEvent;
3
 import android.view.MotionEvent;
4
 import android.widget.ScrollView;
4
 import android.widget.ScrollView;
5
 
5
 
6
-public class ScrollListener implements ScrollViewDelegate.OnScrollListener {
6
+import com.reactnativenavigation.params.CollapsingTopBarParams.CollapseBehaviour;
7
+
8
+public class ScrollListener {
7
     private CollapseCalculator collapseCalculator;
9
     private CollapseCalculator collapseCalculator;
8
     private OnScrollListener scrollListener;
10
     private OnScrollListener scrollListener;
11
+    private CollapseBehaviour collapseBehaviour;
9
 
12
 
10
-    public interface  OnScrollListener {
11
-        void onScroll(float amount);
12
-    }
13
-
14
-    public ScrollListener(CollapsingView collapsingView, OnScrollListener scrollListener) {
15
-        this.collapseCalculator = new CollapseCalculator(collapsingView);
13
+    public ScrollListener(CollapseCalculator collapseCalculator, OnScrollListener scrollListener,
14
+                          CollapseBehaviour collapseBehaviour) {
15
+        this.collapseCalculator = collapseCalculator;
16
         this.scrollListener = scrollListener;
16
         this.scrollListener = scrollListener;
17
+        this.collapseBehaviour = collapseBehaviour;
18
+        collapseCalculator.setFlingListener(scrollListener);
17
     }
19
     }
18
 
20
 
19
-    @Override
20
-    public void onScrollViewAdded(ScrollView scrollView) {
21
+    void onScrollViewAdded(ScrollView scrollView) {
21
         collapseCalculator.setScrollView(scrollView);
22
         collapseCalculator.setScrollView(scrollView);
22
     }
23
     }
23
 
24
 
24
-    @Override
25
-    public boolean onTouch(MotionEvent event) {
25
+    boolean onTouch(MotionEvent event) {
26
         CollapseAmount amount = collapseCalculator.calculate(event);
26
         CollapseAmount amount = collapseCalculator.calculate(event);
27
         if (amount.canCollapse()) {
27
         if (amount.canCollapse()) {
28
-            scrollListener.onScroll(amount.get());
29
-            return true;
28
+            scrollListener.onScroll(amount);
29
+            return CollapseBehaviour.CollapseTopBar.equals(collapseBehaviour);
30
         }
30
         }
31
         return false;
31
         return false;
32
     }
32
     }

+ 18
- 11
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollViewDelegate.java 查看文件

5
 import android.widget.ScrollView;
5
 import android.widget.ScrollView;
6
 
6
 
7
 public class ScrollViewDelegate implements View.OnTouchListener {
7
 public class ScrollViewDelegate implements View.OnTouchListener {
8
-    interface OnScrollListener {
9
-        boolean onTouch(MotionEvent event);
8
+    private ScrollView scrollView;
9
+    private ScrollListener listener;
10
 
10
 
11
-        void onScrollViewAdded(ScrollView scrollView);
11
+    public ScrollViewDelegate(ScrollListener scrollListener) {
12
+        listener = scrollListener;
12
     }
13
     }
13
 
14
 
14
-    private ScrollView scrollView;
15
-    private OnScrollListener listener;
16
-    private Boolean didInterceptLastTouchEvent = null;
15
+    public boolean hasScrollView() {
16
+        return scrollView != null;
17
+    }
17
 
18
 
18
-    public ScrollViewDelegate(OnScrollListener scrollListener) {
19
-        listener = scrollListener;
19
+    public ScrollView getScrollView() {
20
+        return scrollView;
20
     }
21
     }
21
 
22
 
22
     public void onScrollViewAdded(ScrollView scrollView) {
23
     public void onScrollViewAdded(ScrollView scrollView) {
24
         listener.onScrollViewAdded(this.scrollView);
25
         listener.onScrollViewAdded(this.scrollView);
25
     }
26
     }
26
 
27
 
28
+    public void onScrollViewRemoved() {
29
+        this.scrollView = null;
30
+    }
31
+
27
     public boolean didInterceptTouchEvent(MotionEvent ev) {
32
     public boolean didInterceptTouchEvent(MotionEvent ev) {
28
             return listener.onTouch(ev);
33
             return listener.onTouch(ev);
29
     }
34
     }
30
 
35
 
31
     @Override
36
     @Override
32
     public boolean onTouch(View view, MotionEvent event) {
37
     public boolean onTouch(View view, MotionEvent event) {
33
-        if (!didInterceptLastTouchEvent) {
34
-            scrollView.onTouchEvent(event);
35
-        }
38
+        scrollView.onTouchEvent(event);
36
         return this.listener.onTouch(event);
39
         return this.listener.onTouch(event);
37
     }
40
     }
41
+
42
+    public void destroy() {
43
+        scrollView = null;
44
+    }
38
 }
45
 }

+ 57
- 0
android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ViewCollapser.java 查看文件

1
+package com.reactnativenavigation.views.collapsingToolbar;
2
+
3
+import android.animation.Animator;
4
+import android.animation.AnimatorListenerAdapter;
5
+
6
+public class ViewCollapser {
7
+    private static final int DURATION = 160;
8
+    private CollapsingView view;
9
+    private boolean animating;
10
+
11
+    public ViewCollapser(CollapsingView view) {
12
+        this.view = view;
13
+    }
14
+
15
+    public void collapse(CollapseAmount amount) {
16
+        if (amount.collapseToTop()) {
17
+            collapseView(true, view.getFinalCollapseValue());
18
+        } else if (amount.collapseToBottom()) {
19
+            collapseView(true, 0);
20
+        } else {
21
+            collapse(amount.get());
22
+        }
23
+    }
24
+
25
+    public void collapse(float amount) {
26
+        view.asView().setTranslationY(amount);
27
+    }
28
+
29
+    private void collapseView(boolean animate, float translation) {
30
+        if (animate) {
31
+            animate(translation);
32
+        } else {
33
+            view.asView().setTranslationY(translation);
34
+        }
35
+    }
36
+
37
+    private void animate(final float translation) {
38
+        if (animating) {
39
+            return;
40
+        }
41
+        view.asView().animate()
42
+                .translationY(translation)
43
+                .setDuration(DURATION)
44
+                .setListener(new AnimatorListenerAdapter() {
45
+                    @Override
46
+                    public void onAnimationStart(Animator animation) {
47
+                        animating = true;
48
+                    }
49
+
50
+                    @Override
51
+                    public void onAnimationEnd(Animator animation) {
52
+                        animating = false;
53
+                    }
54
+                })
55
+                .start();
56
+    }
57
+}

+ 64
- 0
android/app/src/main/java/com/reactnativenavigation/views/utils/ScrollViewDetector.java 查看文件

1
+package com.reactnativenavigation.views.utils;
2
+
3
+import android.view.View;
4
+import android.view.ViewGroup;
5
+import android.widget.ScrollView;
6
+
7
+import com.reactnativenavigation.utils.ViewUtils;
8
+import com.reactnativenavigation.views.ContentView;
9
+import com.reactnativenavigation.views.collapsingToolbar.OnScrollViewAddedListener;
10
+import com.reactnativenavigation.views.collapsingToolbar.ScrollViewDelegate;
11
+
12
+public class ScrollViewDetector {
13
+    private OnScrollViewAddedListener scrollViewAddedListener;
14
+    private ScrollViewDelegate scrollViewDelegate;
15
+    private View.OnAttachStateChangeListener stateChangeListener;
16
+
17
+    public ScrollViewDetector(final ContentView contentView,
18
+                              OnScrollViewAddedListener onScrollViewAddedListener,
19
+                              final ScrollViewDelegate scrollViewDelegate) {
20
+        this.scrollViewAddedListener = onScrollViewAddedListener;
21
+        this.scrollViewDelegate = scrollViewDelegate;
22
+        stateChangeListener = new View.OnAttachStateChangeListener() {
23
+            @Override
24
+            public void onViewAttachedToWindow(View v) {
25
+
26
+            }
27
+
28
+            @Override
29
+            public void onViewDetachedFromWindow(View v) {
30
+                scrollViewDelegate.getScrollView().removeOnAttachStateChangeListener(this);
31
+                scrollViewDelegate.onScrollViewRemoved();
32
+                contentView.post(new Runnable() {
33
+                    @Override
34
+                    public void run() {
35
+                        detectScrollViewAdded(contentView);
36
+                    }
37
+                });
38
+            }
39
+        };
40
+    }
41
+
42
+    public void detectScrollViewAdded(View child) {
43
+        if (child instanceof ScrollView) {
44
+            onScrollViewAdded((ScrollView) child);
45
+        } else if (child instanceof ViewGroup) {
46
+            Object maybeScrollView = ViewUtils.findChildByClass((ViewGroup) child, ScrollView.class);
47
+            if (maybeScrollView instanceof ScrollView) {
48
+                onScrollViewAdded((ScrollView) maybeScrollView);
49
+            }
50
+        }
51
+    }
52
+
53
+    private void onScrollViewAdded(final ScrollView scrollView) {
54
+        if (scrollViewDelegate != null && !scrollViewDelegate.hasScrollView()) {
55
+            scrollViewDelegate.onScrollViewAdded(scrollView);
56
+            scrollViewAddedListener.onScrollViewAdded(scrollView);
57
+            scrollView.addOnAttachStateChangeListener(stateChangeListener);
58
+        }
59
+    }
60
+
61
+    public void destroy() {
62
+        scrollViewDelegate.getScrollView().removeOnAttachStateChangeListener(stateChangeListener);
63
+    }
64
+}

二进制
android/app/src/main/res/drawable-hdpi/ic_action_name.png 查看文件


二进制
android/app/src/main/res/drawable-hdpi/search.png 查看文件


二进制
android/app/src/main/res/drawable-mdpi/ic_action_name.png 查看文件


二进制
android/app/src/main/res/drawable-mdpi/search.png 查看文件


二进制
android/app/src/main/res/drawable-xhdpi/ic_action_name.png 查看文件


二进制
android/app/src/main/res/drawable-xhdpi/search.png 查看文件


二进制
android/app/src/main/res/drawable-xxhdpi/ic_action_name.png 查看文件


二进制
android/app/src/main/res/drawable-xxhdpi/search.png 查看文件


+ 10
- 0
android/app/src/main/res/menu/search_item.xml 查看文件

1
+<?xml version="1.0" encoding="utf-8"?>
2
+<menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android">
3
+    <item
4
+        android:id="@+id/toolbar_action_search"
5
+        android:title="Search"
6
+        android:icon="@drawable/search"
7
+        app:showAsAction="always|collapseActionView"
8
+        android:iconifiedByDefault="true"
9
+        app:actionViewClass="android.support.v7.widget.SearchView"/>
10
+</menu>

+ 2
- 0
src/deprecated/platformSpecificDeprecated.android.js 查看文件

117
     statusBarColor: originalStyleObject.statusBarColor,
117
     statusBarColor: originalStyleObject.statusBarColor,
118
     topBarColor: originalStyleObject.navBarBackgroundColor,
118
     topBarColor: originalStyleObject.navBarBackgroundColor,
119
     topBarTransparent: originalStyleObject.navBarTransparent,
119
     topBarTransparent: originalStyleObject.navBarTransparent,
120
+    topBarTranslucent: originalStyleObject.navBarTranslucent,
120
     collapsingToolBarImage: originalStyleObject.collapsingToolBarImage,
121
     collapsingToolBarImage: originalStyleObject.collapsingToolBarImage,
121
     collapsingToolBarCollapsedColor: originalStyleObject.collapsingToolBarCollapsedColor,
122
     collapsingToolBarCollapsedColor: originalStyleObject.collapsingToolBarCollapsedColor,
122
     titleBarHidden: originalStyleObject.navBarHidden,
123
     titleBarHidden: originalStyleObject.navBarHidden,
124
+    titleBarHideOnScroll: originalStyleObject.navBarHideOnScroll,
123
     titleBarTitleColor: originalStyleObject.navBarTextColor,
125
     titleBarTitleColor: originalStyleObject.navBarTextColor,
124
     titleBarSubtitleColor: originalStyleObject.navBarTextSubtitleColor,
126
     titleBarSubtitleColor: originalStyleObject.navBarTextSubtitleColor,
125
     titleBarButtonColor: originalStyleObject.navBarButtonColor,
127
     titleBarButtonColor: originalStyleObject.navBarButtonColor,