@sdcx/bottom-sheet 0.17.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -51
- package/RNBottomSheet.podspec +5 -4
- package/android/build.gradle +42 -19
- package/android/src/main/java/com/reactnative/bottomsheet/BottomSheet.java +62 -59
- package/android/src/main/java/com/reactnative/bottomsheet/BottomSheetManager.java +12 -6
- package/android/src/main/java/com/reactnative/bottomsheet/{BottomSheetState.java → BottomSheetStatus.java} +1 -1
- package/android/src/main/java/com/reactnative/bottomsheet/{OffsetChangedEvent.java → OnSlideEvent.java} +5 -3
- package/android/src/main/java/com/reactnative/bottomsheet/{StateChangedEvent.java → OnStateChangedEvent.java} +5 -3
- package/dist/BottomSheetNativeComponent.d.ts +20 -0
- package/dist/BottomSheetNativeComponent.js +2 -0
- package/dist/index.d.ts +8 -15
- package/dist/index.js +9 -9
- package/ios/BottomSheet/{RNBottomSheetOffsetChangedEvent.m → Event/RNBottomSheetOffsetChangedEvent.mm} +3 -1
- package/ios/BottomSheet/{RNBottomSheetStateChangedEvent.h → Event/RNBottomSheetStateChangedEvent.h} +1 -3
- package/ios/BottomSheet/{RNBottomSheetStateChangedEvent.m → Event/RNBottomSheetStateChangedEvent.mm} +4 -4
- package/ios/BottomSheet/RNBottomSheetComponentView.h +10 -0
- package/ios/BottomSheet/RNBottomSheetComponentView.mm +559 -0
- package/package.json +50 -38
- package/src/BottomSheetNativeComponent.ts +26 -0
- package/src/index.tsx +51 -70
- package/docs/assets/pagerview.gif +0 -0
- package/docs/assets/scrollview.gif +0 -0
- package/docs/assets/struct.png +0 -0
- package/ios/BottomSheet/RNBottomSheet.h +0 -21
- package/ios/BottomSheet/RNBottomSheet.m +0 -407
- package/ios/BottomSheet/RNBottomSheetManager.h +0 -9
- package/ios/BottomSheet/RNBottomSheetManager.m +0 -24
- package/ios/BottomSheet/RNBottomSheetState.h +0 -17
- package/ios/BottomSheet/RNBottomSheetState.m +0 -38
- /package/ios/BottomSheet/{RNBottomSheetOffsetChangedEvent.h → Event/RNBottomSheetOffsetChangedEvent.h} +0 -0
package/README.md
CHANGED
|
@@ -4,9 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
它位于屏幕底部,可拖拽,支持嵌套滚动,可以和可滚动视图(`FlatList`, `FlashList`, `WebView` 等等)一起使用。
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
<img src="https://raw.githubusercontent.com/sdcxtech/react-native-troika/master/packages/bottom-sheet/docs/assets/scrollview.gif" width="320">
|
|
8
|
+
<img src="https://raw.githubusercontent.com/sdcxtech/react-native-troika/master/packages/bottom-sheet/docs/assets/pagerview.gif" width="320">
|
|
9
|
+
|
|
10
|
+
## 版本兼容
|
|
11
|
+
|
|
12
|
+
| 版本 | RN 版本 | RN 架构 |
|
|
13
|
+
| ---- | ------- | ------- |
|
|
14
|
+
| 0.x | < 0.82 | 旧架构 |
|
|
15
|
+
| 1.x | >= 0.82 | 新架构 |
|
|
10
16
|
|
|
11
17
|
## Installation
|
|
12
18
|
|
|
@@ -21,26 +27,26 @@ pod install
|
|
|
21
27
|
`BottomSheet` 在使用上是非常简单的,几乎没有什么心智负担。
|
|
22
28
|
|
|
23
29
|
```tsx
|
|
24
|
-
import BottomSheet from '@sdcx/bottom-sheet'
|
|
30
|
+
import BottomSheet from '@sdcx/bottom-sheet';
|
|
25
31
|
|
|
26
32
|
const App = () => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
33
|
+
return (
|
|
34
|
+
<View style={styles.container}>
|
|
35
|
+
<ScrollView>...</ScrollView>
|
|
36
|
+
<BottomSheet peeekHeight={200}>
|
|
37
|
+
{
|
|
38
|
+
// 在这里放置你的内容,可以是任何组件,如:
|
|
39
|
+
}
|
|
40
|
+
<View />
|
|
41
|
+
<PagerView>
|
|
42
|
+
<FlatList nestedScrollEnabled />
|
|
43
|
+
<ScrollView nestedScrollEnabled />
|
|
44
|
+
<WebView />
|
|
45
|
+
</PagerView>
|
|
46
|
+
</BottomSheet>
|
|
47
|
+
</View>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
44
50
|
```
|
|
45
51
|
|
|
46
52
|
> :exclamation: :exclamation: :exclamation:
|
|
@@ -54,53 +60,53 @@ const App = () => {
|
|
|
54
60
|
|
|
55
61
|
`BottomSheet` 由内外两层视图组成,外层是绝对定位,默认填满父组件,除非设置了 `top` 样式属性,内层也是绝对定位,默认填满外层视图。外层的位置固定不变,内层则可拖动。
|
|
56
62
|
|
|
57
|
-

|
|
58
64
|
|
|
59
65
|
`BottomSheet` 拥有 3 个属性和两个回调。
|
|
60
66
|
|
|
61
67
|
### 属性
|
|
62
68
|
|
|
63
|
-
-
|
|
69
|
+
- `peekHeight`, 是指 BottomSheet 收起时,在屏幕上露出的高度,默认是 200。
|
|
64
70
|
|
|
65
|
-
-
|
|
71
|
+
- `state`, 是指 BottomSheet 的状态,有三种状态:
|
|
66
72
|
|
|
67
|
-
|
|
73
|
+
- `'collapsed'`,收起状态,此时 BottomSheet 的高度为 `peekHeight`。
|
|
68
74
|
|
|
69
|
-
|
|
75
|
+
- `'expanded'`,展开状态,此时 BottomSheet 的高度为父组件的高度或内容的高度,参考 `fitToContents` 属性。
|
|
70
76
|
|
|
71
|
-
|
|
77
|
+
- `'hidden'`,隐藏状态,此时 BottomSheet 的高度为 0。
|
|
72
78
|
|
|
73
|
-
-
|
|
79
|
+
- `fitToContents`,是指 BottomSheet 在展开时,是否适应内容的高度,默认是 `false`。当和可滚动列表,譬如 ScrollView 一起使用时,请保持默认值。
|
|
74
80
|
|
|
75
|
-
-
|
|
81
|
+
- `contentContainerStyle`,用来设置内层视图的样式。
|
|
76
82
|
|
|
77
83
|
### 回调
|
|
78
84
|
|
|
79
|
-
-
|
|
85
|
+
- `onStateChanged`, 是指 BottomSheet 状态变化时的回调,它和 `state` 属性是一对,用来实现受控模式。
|
|
80
86
|
|
|
81
|
-
|
|
82
|
-
|
|
87
|
+
```tsx
|
|
88
|
+
export type BottomSheetState = 'collapsed' | 'expanded' | 'hidden';
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
export interface StateChangedEventData {
|
|
91
|
+
state: BottomSheetState;
|
|
92
|
+
}
|
|
87
93
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
interface NativeBottomSheetProps extends ViewProps {
|
|
95
|
+
onStateChanged?: (event: NativeSyntheticEvent<StateChangedEventData>) => void;
|
|
96
|
+
}
|
|
97
|
+
```
|
|
92
98
|
|
|
93
|
-
-
|
|
99
|
+
- `onSlide`, 是指 BottomSheet 滑动时的回调,可以用它来实现一些动画效果。
|
|
94
100
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
```tsx
|
|
102
|
+
export interface OffsetChangedEventData {
|
|
103
|
+
progress: number; // 是指 `BottomSheet` 当前的位置在 `collapsedOffset` 和 `expandedOffset` 之间的比例,它的值在 0 和 1 之间。
|
|
104
|
+
offset: number; // 是指 `BottomSheet` 当前的位置,它的值在 `collapsedOffset` 和 `expandedOffset` 之间。
|
|
105
|
+
expandedOffset: number; // 是指 `BottomSheet` 完全展开时,内层顶部距离外层顶部的距离,通常是 0。但如果设置了 `fitToContents` 属性,则可能大于 0。
|
|
106
|
+
collapsedOffset: number; // 是指 `BottomSheet` 完全收起时,内层顶部距离外层顶部的距离。可以看到,它的值等于外层的高度减去 `peekHeight`。
|
|
107
|
+
}
|
|
102
108
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
109
|
+
interface NativeBottomSheetProps extends ViewProps {
|
|
110
|
+
onSlide?: (event: NativeSyntheticEvent<OffsetChangedEventData>) => void;
|
|
111
|
+
}
|
|
112
|
+
```
|
package/RNBottomSheet.podspec
CHANGED
|
@@ -6,13 +6,14 @@ Pod::Spec.new do |s|
|
|
|
6
6
|
s.name = "RNBottomSheet"
|
|
7
7
|
s.version = package["version"]
|
|
8
8
|
s.summary = package["description"]
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
s.homepage = package["homepage"]
|
|
11
11
|
s.license = package["license"]
|
|
12
12
|
s.authors = package["author"]
|
|
13
|
-
s.platforms = { :ios =>
|
|
13
|
+
s.platforms = { :ios => min_ios_version_supported }
|
|
14
14
|
s.source = { :git => "https://github.com/github-account/bottom-sheet.git", :tag => "#{s.version}" }
|
|
15
15
|
|
|
16
16
|
s.source_files = "ios/BottomSheet/**/*.{h,m,mm}"
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
install_modules_dependencies(s)
|
|
19
|
+
end
|
package/android/build.gradle
CHANGED
|
@@ -1,35 +1,58 @@
|
|
|
1
|
-
// android/build.gradle
|
|
2
1
|
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
buildscript {
|
|
3
|
+
repositories {
|
|
4
|
+
mavenCentral()
|
|
5
|
+
google()
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
dependencies {
|
|
9
|
+
classpath "com.android.tools.build:gradle:8.7.2"
|
|
10
|
+
}
|
|
5
11
|
}
|
|
6
12
|
|
|
7
13
|
apply plugin: 'com.android.library'
|
|
14
|
+
apply plugin: 'com.facebook.react'
|
|
15
|
+
|
|
16
|
+
def safeExtGet(prop, fallback) {
|
|
17
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
18
|
+
}
|
|
8
19
|
|
|
9
20
|
android {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
21
|
+
|
|
22
|
+
def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
|
|
23
|
+
// Check AGP version for backward compatibility w/react-native versions still on gradle plugin 6
|
|
24
|
+
def major = agpVersion[0].toInteger()
|
|
25
|
+
def minor = agpVersion[1].toInteger()
|
|
26
|
+
if ((major == 7 && minor >= 3) || major >= 8) {
|
|
27
|
+
namespace "com.reactnative.bottomsheet"
|
|
28
|
+
buildFeatures {
|
|
29
|
+
buildConfig true
|
|
13
30
|
}
|
|
31
|
+
}
|
|
14
32
|
|
|
15
|
-
|
|
16
|
-
|
|
33
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 35)
|
|
34
|
+
buildToolsVersion safeExtGet('buildToolsVersion', '35.0.0')
|
|
17
35
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
versionName "1.0.0"
|
|
23
|
-
}
|
|
36
|
+
defaultConfig {
|
|
37
|
+
minSdkVersion safeExtGet('minSdkVersion', 24)
|
|
38
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 35)
|
|
39
|
+
}
|
|
24
40
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
41
|
+
sourceSets {
|
|
42
|
+
main {
|
|
43
|
+
java.srcDirs += [
|
|
44
|
+
"generated/java",
|
|
45
|
+
"generated/jni"
|
|
46
|
+
]
|
|
28
47
|
}
|
|
29
48
|
}
|
|
30
49
|
}
|
|
31
50
|
|
|
51
|
+
repositories {
|
|
52
|
+
google()
|
|
53
|
+
mavenCentral()
|
|
54
|
+
}
|
|
55
|
+
|
|
32
56
|
dependencies {
|
|
33
|
-
|
|
34
|
-
implementation 'com.facebook.react:react-native:+'
|
|
57
|
+
api 'com.facebook.react:react-native:+'
|
|
35
58
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
package com.reactnative.bottomsheet;
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
import static com.reactnative.bottomsheet.
|
|
5
|
-
import static com.reactnative.bottomsheet.
|
|
6
|
-
import static com.reactnative.bottomsheet.
|
|
7
|
-
import static com.reactnative.bottomsheet.
|
|
8
|
-
import static com.reactnative.bottomsheet.
|
|
4
|
+
import static com.reactnative.bottomsheet.BottomSheetStatus.COLLAPSED;
|
|
5
|
+
import static com.reactnative.bottomsheet.BottomSheetStatus.DRAGGING;
|
|
6
|
+
import static com.reactnative.bottomsheet.BottomSheetStatus.EXPANDED;
|
|
7
|
+
import static com.reactnative.bottomsheet.BottomSheetStatus.HIDDEN;
|
|
8
|
+
import static com.reactnative.bottomsheet.BottomSheetStatus.SETTLING;
|
|
9
9
|
import static java.lang.Math.max;
|
|
10
10
|
|
|
11
11
|
import android.annotation.SuppressLint;
|
|
@@ -51,7 +51,7 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
51
51
|
this.nestedScrollingParentHelper = new NestedScrollingParentHelper(this);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
private
|
|
54
|
+
private BottomSheetStatus status = COLLAPSED;
|
|
55
55
|
|
|
56
56
|
private SettleRunnable settleRunnable = null;
|
|
57
57
|
|
|
@@ -114,11 +114,11 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
114
114
|
|
|
115
115
|
getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
|
|
116
116
|
int top = contentView.getTop();
|
|
117
|
-
if (
|
|
117
|
+
if (status == COLLAPSED) {
|
|
118
118
|
child.offsetTopAndBottom(collapsedOffset - top);
|
|
119
|
-
} else if (
|
|
119
|
+
} else if (status == EXPANDED) {
|
|
120
120
|
child.offsetTopAndBottom(expandedOffset - top);
|
|
121
|
-
} else if (
|
|
121
|
+
} else if (status == HIDDEN) {
|
|
122
122
|
child.offsetTopAndBottom(getHeight() - top);
|
|
123
123
|
}
|
|
124
124
|
getViewTreeObserver().addOnPreDrawListener(preDrawListener);
|
|
@@ -152,8 +152,8 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
152
152
|
this.peekHeight = max(peekHeight, 0);
|
|
153
153
|
if (contentView != null) {
|
|
154
154
|
calculateOffset();
|
|
155
|
-
if (
|
|
156
|
-
|
|
155
|
+
if (status == COLLAPSED) {
|
|
156
|
+
settleToStatus(contentView, status);
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
}
|
|
@@ -162,19 +162,19 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
162
162
|
this.draggable = draggable;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
public void
|
|
166
|
-
if (this.
|
|
165
|
+
public void setStatus(BottomSheetStatus status) {
|
|
166
|
+
if (this.status == status || this.status == SETTLING) {
|
|
167
167
|
return;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
if (contentView == null) {
|
|
171
171
|
// The view is not laid out yet; modify mState and let onLayoutChild handle it later
|
|
172
|
-
if (
|
|
173
|
-
this.
|
|
172
|
+
if (status == COLLAPSED || status == EXPANDED || status == HIDDEN) {
|
|
173
|
+
this.status = status;
|
|
174
174
|
}
|
|
175
175
|
return;
|
|
176
176
|
}
|
|
177
|
-
|
|
177
|
+
settleToStatus(contentView, status);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
@Nullable
|
|
@@ -203,12 +203,13 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
203
203
|
return null;
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
@NonNull
|
|
206
207
|
public PointerEvents getPointerEvents() {
|
|
207
208
|
return PointerEvents.BOX_NONE;
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
@Override
|
|
211
|
-
public boolean onInterceptTouchEvent(MotionEvent event) {
|
|
212
|
+
public boolean onInterceptTouchEvent(@NonNull MotionEvent event) {
|
|
212
213
|
if (shouldInterceptTouchEvent(event)) {
|
|
213
214
|
NativeGestureUtil.notifyNativeGestureStarted(this, event);
|
|
214
215
|
return true;
|
|
@@ -220,6 +221,7 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
220
221
|
if (!draggable) {
|
|
221
222
|
return false;
|
|
222
223
|
}
|
|
224
|
+
|
|
223
225
|
int action = event.getActionMasked();
|
|
224
226
|
// Record the velocity
|
|
225
227
|
if (action == MotionEvent.ACTION_DOWN) {
|
|
@@ -246,7 +248,7 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
246
248
|
initialY = (int) event.getY();
|
|
247
249
|
// Only intercept nested scrolling events here if the view not being moved by the
|
|
248
250
|
// ViewDragHelper.
|
|
249
|
-
if (
|
|
251
|
+
if (status != SETTLING) {
|
|
250
252
|
View scroll = nestedScrollingChildRef != null ? nestedScrollingChildRef.get() : null;
|
|
251
253
|
if (scroll != null && isPointInChildBounds(scroll, initialX, initialY)) {
|
|
252
254
|
activePointerId = event.getPointerId(event.getActionIndex());
|
|
@@ -271,20 +273,21 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
271
273
|
return action == MotionEvent.ACTION_MOVE
|
|
272
274
|
&& scroll != null
|
|
273
275
|
&& !ignoreEvents
|
|
274
|
-
&&
|
|
276
|
+
&& status != DRAGGING
|
|
275
277
|
&& !isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY())
|
|
276
278
|
&& viewDragHelper != null
|
|
277
279
|
&& Math.abs(initialY - event.getY()) > viewDragHelper.getTouchSlop();
|
|
278
280
|
}
|
|
279
281
|
|
|
280
|
-
@
|
|
281
|
-
|
|
282
|
+
@SuppressLint("ClickableViewAccessibility")
|
|
283
|
+
@Override
|
|
284
|
+
public boolean onTouchEvent(@NonNull MotionEvent event) {
|
|
282
285
|
if (!draggable) {
|
|
283
286
|
return false;
|
|
284
287
|
}
|
|
285
288
|
|
|
286
289
|
int action = event.getActionMasked();
|
|
287
|
-
if (
|
|
290
|
+
if (status == DRAGGING && action == MotionEvent.ACTION_DOWN) {
|
|
288
291
|
return true;
|
|
289
292
|
}
|
|
290
293
|
if (viewDragHelper != null) {
|
|
@@ -332,22 +335,22 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
332
335
|
if (newTop < expandedOffset) {
|
|
333
336
|
consumed[1] = currentTop - expandedOffset;
|
|
334
337
|
ViewCompat.offsetTopAndBottom(child, -consumed[1]);
|
|
335
|
-
|
|
338
|
+
setStatusInternal(EXPANDED);
|
|
336
339
|
} else {
|
|
337
340
|
consumed[1] = dy;
|
|
338
341
|
ViewCompat.offsetTopAndBottom(child, -dy);
|
|
339
|
-
|
|
342
|
+
setStatusInternal(DRAGGING);
|
|
340
343
|
}
|
|
341
344
|
} else if (dy < 0) { // Downward
|
|
342
345
|
if (!target.canScrollVertically(-1)) {
|
|
343
346
|
if (newTop <= collapsedOffset) {
|
|
344
347
|
consumed[1] = dy;
|
|
345
348
|
ViewCompat.offsetTopAndBottom(child, -dy);
|
|
346
|
-
|
|
349
|
+
setStatusInternal(DRAGGING);
|
|
347
350
|
} else {
|
|
348
351
|
consumed[1] = currentTop - collapsedOffset;
|
|
349
352
|
ViewCompat.offsetTopAndBottom(child, -consumed[1]);
|
|
350
|
-
|
|
353
|
+
setStatusInternal(COLLAPSED);
|
|
351
354
|
}
|
|
352
355
|
}
|
|
353
356
|
}
|
|
@@ -368,7 +371,7 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
368
371
|
View child = contentView;
|
|
369
372
|
|
|
370
373
|
if (child.getTop() == expandedOffset) {
|
|
371
|
-
|
|
374
|
+
setStatusInternal(EXPANDED);
|
|
372
375
|
return;
|
|
373
376
|
}
|
|
374
377
|
|
|
@@ -377,7 +380,7 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
377
380
|
}
|
|
378
381
|
|
|
379
382
|
int top;
|
|
380
|
-
|
|
383
|
+
BottomSheetStatus targetState;
|
|
381
384
|
|
|
382
385
|
if (lastNestedScrollDy > 0) {
|
|
383
386
|
top = expandedOffset;
|
|
@@ -407,7 +410,7 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
407
410
|
@Override
|
|
408
411
|
public boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY) {
|
|
409
412
|
if (nestedScrollingChildRef != null) {
|
|
410
|
-
return target == nestedScrollingChildRef.get() && (
|
|
413
|
+
return target == nestedScrollingChildRef.get() && (status != EXPANDED);
|
|
411
414
|
} else {
|
|
412
415
|
return false;
|
|
413
416
|
}
|
|
@@ -455,13 +458,13 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
455
458
|
private final ViewDragHelper.Callback dragCallback = new ViewDragHelper.Callback() {
|
|
456
459
|
@Override
|
|
457
460
|
public boolean tryCaptureView(@NonNull View child, int pointerId) {
|
|
458
|
-
if (
|
|
461
|
+
if (status == DRAGGING) {
|
|
459
462
|
return false;
|
|
460
463
|
}
|
|
461
464
|
if (touchingScrollingChild) {
|
|
462
465
|
return false;
|
|
463
466
|
}
|
|
464
|
-
if (
|
|
467
|
+
if (status == EXPANDED && activePointerId == pointerId) {
|
|
465
468
|
View scroll = nestedScrollingChildRef != null ? nestedScrollingChildRef.get() : null;
|
|
466
469
|
if (scroll != null && scroll.canScrollVertically(-1)) {
|
|
467
470
|
// Let the content scroll up
|
|
@@ -479,14 +482,14 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
479
482
|
@Override
|
|
480
483
|
public void onViewDragStateChanged(int state) {
|
|
481
484
|
if (state == ViewDragHelper.STATE_DRAGGING) {
|
|
482
|
-
|
|
485
|
+
setStatusInternal(DRAGGING);
|
|
483
486
|
}
|
|
484
487
|
}
|
|
485
488
|
|
|
486
489
|
@Override
|
|
487
490
|
public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
|
|
488
491
|
int top;
|
|
489
|
-
|
|
492
|
+
BottomSheetStatus targetState;
|
|
490
493
|
if (yvel < 0) { // Moving up
|
|
491
494
|
top = expandedOffset;
|
|
492
495
|
targetState = EXPANDED;
|
|
@@ -527,60 +530,60 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
527
530
|
|
|
528
531
|
void dispatchOnSlide(int top) {
|
|
529
532
|
if (contentView != null) {
|
|
530
|
-
sentEvent(new
|
|
533
|
+
sentEvent(new OnSlideEvent(UIManagerHelper.getSurfaceId(reactContext), getId(), top, expandedOffset, collapsedOffset));
|
|
531
534
|
}
|
|
532
535
|
}
|
|
533
536
|
|
|
534
|
-
void
|
|
537
|
+
void settleToStatus(@NonNull View child, BottomSheetStatus status) {
|
|
535
538
|
int top;
|
|
536
|
-
if (
|
|
539
|
+
if (status == COLLAPSED) {
|
|
537
540
|
top = collapsedOffset;
|
|
538
|
-
} else if (
|
|
541
|
+
} else if (status == EXPANDED) {
|
|
539
542
|
top = expandedOffset;
|
|
540
|
-
} else if (
|
|
543
|
+
} else if (status == HIDDEN) {
|
|
541
544
|
top = getHeight();
|
|
542
545
|
} else {
|
|
543
|
-
throw new IllegalArgumentException("Illegal
|
|
546
|
+
throw new IllegalArgumentException("Illegal status argument: " + status);
|
|
544
547
|
}
|
|
545
|
-
startSettlingAnimation(child,
|
|
548
|
+
startSettlingAnimation(child, status, top, false);
|
|
546
549
|
}
|
|
547
550
|
|
|
548
|
-
void startSettlingAnimation(View child,
|
|
551
|
+
void startSettlingAnimation(View child, BottomSheetStatus status, int top, boolean settleFromViewDragHelper) {
|
|
549
552
|
boolean startedSettling =
|
|
550
553
|
viewDragHelper != null
|
|
551
554
|
&& (settleFromViewDragHelper
|
|
552
555
|
? viewDragHelper.settleCapturedViewAt(child.getLeft(), top)
|
|
553
556
|
: viewDragHelper.smoothSlideViewTo(child, child.getLeft(), top));
|
|
554
557
|
if (startedSettling) {
|
|
555
|
-
|
|
556
|
-
// STATE_SETTLING won't animate the material shape, so do that here with the target
|
|
557
|
-
// updateDrawableForTargetState(
|
|
558
|
+
setStatusInternal(SETTLING);
|
|
559
|
+
// STATE_SETTLING won't animate the material shape, so do that here with the target status.
|
|
560
|
+
// updateDrawableForTargetState(status);
|
|
558
561
|
if (settleRunnable == null) {
|
|
559
562
|
// If the singleton SettleRunnable instance has not been instantiated, create it.
|
|
560
|
-
settleRunnable = new SettleRunnable(child,
|
|
563
|
+
settleRunnable = new SettleRunnable(child, status);
|
|
561
564
|
}
|
|
562
|
-
// If the SettleRunnable has not been posted, post it with the correct
|
|
565
|
+
// If the SettleRunnable has not been posted, post it with the correct status.
|
|
563
566
|
if (!settleRunnable.isPosted) {
|
|
564
|
-
settleRunnable.
|
|
567
|
+
settleRunnable.targetStatus = status;
|
|
565
568
|
ViewCompat.postOnAnimation(child, settleRunnable);
|
|
566
569
|
settleRunnable.isPosted = true;
|
|
567
570
|
} else {
|
|
568
|
-
// Otherwise, if it has been posted, just update the target
|
|
569
|
-
settleRunnable.
|
|
571
|
+
// Otherwise, if it has been posted, just update the target status.
|
|
572
|
+
settleRunnable.targetStatus = status;
|
|
570
573
|
}
|
|
571
574
|
} else {
|
|
572
|
-
|
|
575
|
+
setStatusInternal(status);
|
|
573
576
|
}
|
|
574
577
|
}
|
|
575
578
|
|
|
576
|
-
void
|
|
577
|
-
if (this.
|
|
579
|
+
void setStatusInternal(BottomSheetStatus status) {
|
|
580
|
+
if (this.status == status) {
|
|
578
581
|
return;
|
|
579
582
|
}
|
|
580
|
-
this.
|
|
583
|
+
this.status = status;
|
|
581
584
|
|
|
582
|
-
if (
|
|
583
|
-
sentEvent(new
|
|
585
|
+
if (status == COLLAPSED || status == EXPANDED || status == HIDDEN) {
|
|
586
|
+
sentEvent(new OnStateChangedEvent(UIManagerHelper.getSurfaceId(reactContext), getId(), status.name().toLowerCase()));
|
|
584
587
|
}
|
|
585
588
|
}
|
|
586
589
|
|
|
@@ -590,11 +593,11 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
590
593
|
|
|
591
594
|
private boolean isPosted;
|
|
592
595
|
|
|
593
|
-
|
|
596
|
+
BottomSheetStatus targetStatus;
|
|
594
597
|
|
|
595
|
-
SettleRunnable(View view,
|
|
598
|
+
SettleRunnable(View view, BottomSheetStatus targetStatus) {
|
|
596
599
|
this.view = view;
|
|
597
|
-
this.
|
|
600
|
+
this.targetStatus = targetStatus;
|
|
598
601
|
}
|
|
599
602
|
|
|
600
603
|
@Override
|
|
@@ -602,7 +605,7 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
602
605
|
if (viewDragHelper != null && viewDragHelper.continueSettling(true)) {
|
|
603
606
|
ViewCompat.postOnAnimation(view, this);
|
|
604
607
|
} else {
|
|
605
|
-
|
|
608
|
+
setStatusInternal(targetStatus);
|
|
606
609
|
}
|
|
607
610
|
this.isPosted = false;
|
|
608
611
|
}
|
|
@@ -7,10 +7,12 @@ import com.facebook.react.uimanager.PixelUtil;
|
|
|
7
7
|
import com.facebook.react.uimanager.ThemedReactContext;
|
|
8
8
|
import com.facebook.react.uimanager.ViewGroupManager;
|
|
9
9
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
|
10
|
+
import com.facebook.react.viewmanagers.BottomSheetManagerInterface;
|
|
10
11
|
|
|
11
12
|
import java.util.Map;
|
|
12
13
|
|
|
13
|
-
public class BottomSheetManager extends ViewGroupManager<BottomSheet>
|
|
14
|
+
public class BottomSheetManager extends ViewGroupManager<BottomSheet>
|
|
15
|
+
implements BottomSheetManagerInterface<BottomSheet> {
|
|
14
16
|
|
|
15
17
|
@NonNull
|
|
16
18
|
@Override
|
|
@@ -27,21 +29,25 @@ public class BottomSheetManager extends ViewGroupManager<BottomSheet> {
|
|
|
27
29
|
@Override
|
|
28
30
|
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
|
|
29
31
|
return MapBuilder.<String, Object>builder()
|
|
30
|
-
.put(
|
|
31
|
-
.put(
|
|
32
|
+
.put(OnStateChangedEvent.Name, MapBuilder.of("registrationName", OnStateChangedEvent.JSEventName))
|
|
33
|
+
.put(OnSlideEvent.Name, MapBuilder.of("registrationName", OnSlideEvent.JSEventName))
|
|
32
34
|
.build();
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
@Override
|
|
35
38
|
@ReactProp(name = "peekHeight", defaultInt = 200)
|
|
36
39
|
public void setPeekHeight(BottomSheet view, int dp) {
|
|
37
40
|
view.setPeekHeight((int) (PixelUtil.toPixelFromDIP(dp) + 0.5));
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
@Override
|
|
44
|
+
@ReactProp(name = "status")
|
|
45
|
+
public void setStatus(BottomSheet view, String status) {
|
|
46
|
+
assert status != null;
|
|
47
|
+
view.setStatus(BottomSheetStatus.valueOf(status.toUpperCase()));
|
|
43
48
|
}
|
|
44
49
|
|
|
50
|
+
@Override
|
|
45
51
|
@ReactProp(name = "draggable")
|
|
46
52
|
public void setDraggable(BottomSheet view, boolean draggable) {
|
|
47
53
|
view.setDraggable(draggable);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package com.reactnative.bottomsheet;
|
|
2
2
|
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
3
4
|
import androidx.annotation.Nullable;
|
|
4
5
|
|
|
5
6
|
import com.facebook.react.bridge.Arguments;
|
|
@@ -7,21 +8,22 @@ import com.facebook.react.bridge.WritableMap;
|
|
|
7
8
|
import com.facebook.react.uimanager.PixelUtil;
|
|
8
9
|
import com.facebook.react.uimanager.events.Event;
|
|
9
10
|
|
|
10
|
-
public class
|
|
11
|
-
public static final String Name = "
|
|
11
|
+
public class OnSlideEvent extends Event<OnSlideEvent> {
|
|
12
|
+
public static final String Name = "topSlide";
|
|
12
13
|
public static final String JSEventName = "onSlide";
|
|
13
14
|
|
|
14
15
|
private final int offset;
|
|
15
16
|
private final int minOffset;
|
|
16
17
|
private final int maxOffset;
|
|
17
18
|
|
|
18
|
-
public
|
|
19
|
+
public OnSlideEvent(int surfaceId, int viewTag, int offset, int minOffset, int maxOffset) {
|
|
19
20
|
super(surfaceId, viewTag);
|
|
20
21
|
this.offset = offset;
|
|
21
22
|
this.maxOffset = maxOffset;
|
|
22
23
|
this.minOffset = minOffset;
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
@NonNull
|
|
25
27
|
@Override
|
|
26
28
|
public String getEventName() {
|
|
27
29
|
return Name;
|