@sdcx/bottom-sheet 1.0.5 → 1.0.6
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/RNBottomSheet.podspec +4 -1
- package/android/src/main/java/com/reactnative/bottomsheet/BottomSheet.java +18 -1
- package/android/src/main/java/com/reactnative/bottomsheet/BottomSheetContentView.java +39 -0
- package/android/src/main/java/com/reactnative/bottomsheet/BottomSheetContentViewManager.java +46 -0
- package/android/src/main/java/com/reactnative/bottomsheet/BottomSheetPackage.java +2 -1
- package/android/src/main/jni/CMakeLists.txt +91 -0
- package/android/src/main/jni/bottomsheet.h +17 -0
- package/dist/BottomSheetContentViewNativeComponent.d.ts +5 -0
- package/dist/BottomSheetContentViewNativeComponent.js +4 -0
- package/dist/index.js +4 -3
- package/dist/splitLayoutProps.d.ts +2 -2
- package/ios/RNBottomSheet.mm +23 -2
- package/ios/RNBottomSheetContentView.h +12 -0
- package/ios/RNBottomSheetContentView.mm +47 -0
- package/package.json +3 -2
- package/react-native.config.js +2 -1
- package/src/BottomSheetContentViewNativeComponent.ts +8 -0
- package/src/index.tsx +4 -3
package/RNBottomSheet.podspec
CHANGED
|
@@ -13,7 +13,10 @@ Pod::Spec.new do |s|
|
|
|
13
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
|
-
s.source_files = "ios/**/*.{h,m,mm}"
|
|
16
|
+
s.source_files = "ios/**/*.{h,m,mm}", "common/cpp/**/*.{cpp,h}"
|
|
17
|
+
s.pod_target_xcconfig = {
|
|
18
|
+
"HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/common/cpp\""
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
install_modules_dependencies(s)
|
|
19
22
|
end
|
|
@@ -87,6 +87,9 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
87
87
|
|
|
88
88
|
private int contentHeight = -1;
|
|
89
89
|
|
|
90
|
+
/** 子 View 的布局 top,用于计算 getContentOriginOffset 的差值 (实际 top - layoutContentTop) */
|
|
91
|
+
private int layoutContentTop = -1;
|
|
92
|
+
|
|
90
93
|
@Override
|
|
91
94
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
|
92
95
|
if (viewDragHelper == null) {
|
|
@@ -114,10 +117,20 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
114
117
|
|
|
115
118
|
getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
|
|
116
119
|
int top = contentView.getTop();
|
|
120
|
+
boolean isFirstLayout = layoutContentTop < 0;
|
|
121
|
+
if (layoutContentTop < 0) {
|
|
122
|
+
layoutContentTop = top;
|
|
123
|
+
}
|
|
117
124
|
if (status == COLLAPSED) {
|
|
118
125
|
child.offsetTopAndBottom(collapsedOffset - top);
|
|
119
126
|
} else if (status == EXPANDED) {
|
|
120
|
-
|
|
127
|
+
if (isFirstLayout) {
|
|
128
|
+
// 与 iOS 一致:首次 layout 且为 expanded 时先置于 collapsed 再播放展开动画
|
|
129
|
+
child.offsetTopAndBottom(collapsedOffset - top);
|
|
130
|
+
ViewCompat.postOnAnimation(child, () -> settleToStatus(contentView, EXPANDED));
|
|
131
|
+
} else {
|
|
132
|
+
child.offsetTopAndBottom(expandedOffset - top);
|
|
133
|
+
}
|
|
121
134
|
} else if (status == HIDDEN) {
|
|
122
135
|
child.offsetTopAndBottom(getHeight() - top);
|
|
123
136
|
}
|
|
@@ -530,6 +543,10 @@ public class BottomSheet extends ReactViewGroup implements NestedScrollingParent
|
|
|
530
543
|
|
|
531
544
|
void dispatchOnSlide(int top) {
|
|
532
545
|
if (contentView != null) {
|
|
546
|
+
if (contentView instanceof BottomSheetContentView && layoutContentTop >= 0) {
|
|
547
|
+
int offsetY = top - layoutContentTop;
|
|
548
|
+
((BottomSheetContentView) contentView).updateContentOffset(offsetY);
|
|
549
|
+
}
|
|
533
550
|
sentEvent(new OnSlideEvent(UIManagerHelper.getSurfaceId(reactContext), getId(), top, expandedOffset, collapsedOffset));
|
|
534
551
|
}
|
|
535
552
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
package com.reactnative.bottomsheet;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
|
|
5
|
+
import com.facebook.react.bridge.Arguments;
|
|
6
|
+
import com.facebook.react.bridge.WritableMap;
|
|
7
|
+
import com.facebook.react.uimanager.PixelUtil;
|
|
8
|
+
import com.facebook.react.uimanager.StateWrapper;
|
|
9
|
+
import com.facebook.react.views.view.ReactViewGroup;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Content view for BottomSheet. Implements getContentOriginOffset via state so that
|
|
13
|
+
* hit-testing uses the correct coordinates when the parent BottomSheet moves this view.
|
|
14
|
+
*/
|
|
15
|
+
public class BottomSheetContentView extends ReactViewGroup {
|
|
16
|
+
|
|
17
|
+
@SuppressWarnings("NullableProblems")
|
|
18
|
+
private StateWrapper stateWrapper;
|
|
19
|
+
|
|
20
|
+
public BottomSheetContentView(Context context) {
|
|
21
|
+
super(context);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public void setStateWrapper(StateWrapper wrapper) {
|
|
25
|
+
this.stateWrapper = wrapper;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Updates Fabric state with content offset (actual top - layout top) so that
|
|
30
|
+
* getContentOriginOffset can correct hit-testing. Called by the parent BottomSheet.
|
|
31
|
+
*/
|
|
32
|
+
public void updateContentOffset(int offsetPx) {
|
|
33
|
+
if (stateWrapper != null) {
|
|
34
|
+
WritableMap map = Arguments.createMap();
|
|
35
|
+
map.putDouble("contentOffset", PixelUtil.toDIPFromPixel(offsetPx));
|
|
36
|
+
stateWrapper.updateState(map);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
package com.reactnative.bottomsheet;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
|
|
6
|
+
import com.facebook.react.uimanager.ReactStylesDiffMap;
|
|
7
|
+
import com.facebook.react.uimanager.StateWrapper;
|
|
8
|
+
import com.facebook.react.uimanager.ThemedReactContext;
|
|
9
|
+
import com.facebook.react.uimanager.ViewGroupManager;
|
|
10
|
+
import com.facebook.react.uimanager.ViewManagerDelegate;
|
|
11
|
+
import com.facebook.react.viewmanagers.BottomSheetContentViewManagerDelegate;
|
|
12
|
+
import com.facebook.react.viewmanagers.BottomSheetContentViewManagerInterface;
|
|
13
|
+
|
|
14
|
+
public class BottomSheetContentViewManager extends ViewGroupManager<BottomSheetContentView>
|
|
15
|
+
implements BottomSheetContentViewManagerInterface<BottomSheetContentView> {
|
|
16
|
+
|
|
17
|
+
private final BottomSheetContentViewManagerDelegate<BottomSheetContentView, BottomSheetContentViewManager> mDelegate =
|
|
18
|
+
new BottomSheetContentViewManagerDelegate<>(this);
|
|
19
|
+
|
|
20
|
+
@Override
|
|
21
|
+
protected ViewManagerDelegate<BottomSheetContentView> getDelegate() {
|
|
22
|
+
return mDelegate;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@NonNull
|
|
26
|
+
@Override
|
|
27
|
+
public String getName() {
|
|
28
|
+
return "BottomSheetContentView";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@NonNull
|
|
32
|
+
@Override
|
|
33
|
+
protected BottomSheetContentView createViewInstance(@NonNull ThemedReactContext context) {
|
|
34
|
+
return new BottomSheetContentView(context);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@Nullable
|
|
38
|
+
@Override
|
|
39
|
+
public Object updateState(
|
|
40
|
+
@NonNull BottomSheetContentView view,
|
|
41
|
+
ReactStylesDiffMap props,
|
|
42
|
+
StateWrapper stateWrapper) {
|
|
43
|
+
view.setStateWrapper(stateWrapper);
|
|
44
|
+
return super.updateState(view, props, stateWrapper);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -2,6 +2,7 @@ package com.reactnative.bottomsheet;
|
|
|
2
2
|
|
|
3
3
|
import androidx.annotation.NonNull;
|
|
4
4
|
|
|
5
|
+
import java.util.Arrays;
|
|
5
6
|
import java.util.Collections;
|
|
6
7
|
import java.util.List;
|
|
7
8
|
|
|
@@ -20,6 +21,6 @@ public class BottomSheetPackage implements ReactPackage {
|
|
|
20
21
|
@NonNull
|
|
21
22
|
@Override
|
|
22
23
|
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
|
|
23
|
-
return
|
|
24
|
+
return Arrays.asList(new BottomSheetManager(), new BottomSheetContentViewManager());
|
|
24
25
|
}
|
|
25
26
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.13)
|
|
2
|
+
set(CMAKE_VERBOSE_MAKEFILE ON)
|
|
3
|
+
|
|
4
|
+
set(LIB_LITERAL bottomsheet)
|
|
5
|
+
set(LIB_TARGET_NAME react_codegen_${LIB_LITERAL})
|
|
6
|
+
|
|
7
|
+
set(LIB_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
|
|
8
|
+
set(LIB_COMMON_DIR ${LIB_ANDROID_DIR}/../common/cpp)
|
|
9
|
+
set(LIB_ANDROID_GENERATED_JNI_DIR ${LIB_ANDROID_DIR}/build/generated/source/codegen/jni)
|
|
10
|
+
set(LIB_ANDROID_GENERATED_COMPONENTS_DIR ${LIB_ANDROID_GENERATED_JNI_DIR}/react/renderer/components/${LIB_LITERAL})
|
|
11
|
+
|
|
12
|
+
file(GLOB LIB_CUSTOM_SRCS CONFIGURE_DEPENDS *.cpp ${LIB_COMMON_DIR}/react/renderer/components/${LIB_LITERAL}/*.cpp)
|
|
13
|
+
file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS ${LIB_ANDROID_GENERATED_JNI_DIR}/*.cpp ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}/*.cpp)
|
|
14
|
+
|
|
15
|
+
add_library(
|
|
16
|
+
${LIB_TARGET_NAME}
|
|
17
|
+
SHARED
|
|
18
|
+
${LIB_CUSTOM_SRCS}
|
|
19
|
+
${LIB_CODEGEN_SRCS}
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
target_include_directories(
|
|
23
|
+
${LIB_TARGET_NAME}
|
|
24
|
+
PUBLIC
|
|
25
|
+
.
|
|
26
|
+
${LIB_COMMON_DIR}
|
|
27
|
+
${LIB_ANDROID_GENERATED_JNI_DIR}
|
|
28
|
+
${LIB_ANDROID_GENERATED_COMPONENTS_DIR}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
if (REACTNATIVE_MERGED_SO)
|
|
32
|
+
target_link_libraries(
|
|
33
|
+
${LIB_TARGET_NAME}
|
|
34
|
+
fbjni
|
|
35
|
+
jsi
|
|
36
|
+
reactnative
|
|
37
|
+
)
|
|
38
|
+
else()
|
|
39
|
+
target_link_libraries(
|
|
40
|
+
${LIB_TARGET_NAME}
|
|
41
|
+
fbjni
|
|
42
|
+
folly_runtime
|
|
43
|
+
glog
|
|
44
|
+
jsi
|
|
45
|
+
react_codegen_rncore
|
|
46
|
+
react_debug
|
|
47
|
+
react_render_componentregistry
|
|
48
|
+
react_render_core
|
|
49
|
+
react_render_debug
|
|
50
|
+
react_render_graphics
|
|
51
|
+
react_render_imagemanager
|
|
52
|
+
react_render_mapbuffer
|
|
53
|
+
react_utils
|
|
54
|
+
react_nativemodule_core
|
|
55
|
+
rrc_image
|
|
56
|
+
turbomodulejsijni
|
|
57
|
+
rrc_view
|
|
58
|
+
yoga
|
|
59
|
+
)
|
|
60
|
+
endif()
|
|
61
|
+
|
|
62
|
+
if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 81)
|
|
63
|
+
target_compile_reactnative_options(${LIB_TARGET_NAME} PUBLIC)
|
|
64
|
+
else()
|
|
65
|
+
target_compile_options(
|
|
66
|
+
${LIB_TARGET_NAME}
|
|
67
|
+
PRIVATE
|
|
68
|
+
-fexceptions
|
|
69
|
+
-frtti
|
|
70
|
+
-std=c++20
|
|
71
|
+
-Wall
|
|
72
|
+
-Wpedantic
|
|
73
|
+
-Wno-gnu-zero-variadic-macro-arguments
|
|
74
|
+
)
|
|
75
|
+
endif()
|
|
76
|
+
|
|
77
|
+
target_compile_options(
|
|
78
|
+
${LIB_TARGET_NAME}
|
|
79
|
+
PRIVATE
|
|
80
|
+
-DLOG_TAG=\"ReactNative\"
|
|
81
|
+
-fexceptions
|
|
82
|
+
-frtti
|
|
83
|
+
-std=c++20
|
|
84
|
+
-Wall
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
target_include_directories(
|
|
88
|
+
${CMAKE_PROJECT_NAME}
|
|
89
|
+
PUBLIC
|
|
90
|
+
${CMAKE_CURRENT_SOURCE_DIR}
|
|
91
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <ReactCommon/JavaTurboModule.h>
|
|
4
|
+
#include <ReactCommon/TurboModule.h>
|
|
5
|
+
#include <jsi/jsi.h>
|
|
6
|
+
#include <react/renderer/components/bottomsheet/BottomSheetContentViewComponentDescriptor.h>
|
|
7
|
+
|
|
8
|
+
namespace facebook {
|
|
9
|
+
namespace react {
|
|
10
|
+
|
|
11
|
+
JSI_EXPORT
|
|
12
|
+
std::shared_ptr<TurboModule> bottomsheet_ModuleProvider(
|
|
13
|
+
const std::string &moduleName,
|
|
14
|
+
const JavaTurboModule::InitParams ¶ms);
|
|
15
|
+
|
|
16
|
+
} // namespace react
|
|
17
|
+
} // namespace facebook
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { StyleSheet
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
3
|
import splitLayoutProps from './splitLayoutProps';
|
|
4
4
|
import BottomSheetNativeComponent from './BottomSheetNativeComponent';
|
|
5
|
+
import BottomSheetContentViewNativeComponent from './BottomSheetContentViewNativeComponent';
|
|
5
6
|
function BottomSheet(props) {
|
|
6
7
|
const { style, contentContainerStyle, children, peekHeight = 200, draggable = true, state = 'collapsed', fitToContents, ...rest } = props;
|
|
7
8
|
const { outer, inner } = splitLayoutProps(StyleSheet.flatten(style));
|
|
8
9
|
return (<BottomSheetNativeComponent style={[StyleSheet.absoluteFill, outer]} peekHeight={peekHeight} draggable={draggable} status={state} {...rest}>
|
|
9
|
-
<
|
|
10
|
+
<BottomSheetContentViewNativeComponent style={[
|
|
10
11
|
fitToContents ? styles.fitToContents : StyleSheet.absoluteFill,
|
|
11
12
|
inner,
|
|
12
13
|
contentContainerStyle,
|
|
13
14
|
]} collapsable={false}>
|
|
14
15
|
{children}
|
|
15
|
-
</
|
|
16
|
+
</BottomSheetContentViewNativeComponent>
|
|
16
17
|
</BottomSheetNativeComponent>);
|
|
17
18
|
}
|
|
18
19
|
const styles = StyleSheet.create({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ViewStyle } from 'react-native';
|
|
2
2
|
export default function splitLayoutProps(props?: ViewStyle): {
|
|
3
3
|
outer: {
|
|
4
|
-
[key: string]: string | number | import("react-native").OpaqueColorValue | import("react-native").Animated.AnimatedNode | readonly import("react-native").BoxShadowValue[] | readonly import("react-native").FilterFunction[] | readonly import("react-native").
|
|
4
|
+
[key: string]: string | number | import("react-native").OpaqueColorValue | import("react-native").Animated.AnimatedNode | readonly import("react-native").BoxShadowValue[] | readonly import("react-native").FilterFunction[] | readonly import("react-native").BackgroundImageValue[] | readonly import("react-native").BackgroundSizeValue[] | readonly import("react-native").BackgroundPositionValue[] | readonly import("react-native").BackgroundRepeatValue[] | Readonly<{
|
|
5
5
|
width: number;
|
|
6
6
|
height: number;
|
|
7
7
|
}> | readonly (({
|
|
@@ -202,7 +202,7 @@ export default function splitLayoutProps(props?: ViewStyle): {
|
|
|
202
202
|
}))[] | (string | number)[] | number[] | null | undefined;
|
|
203
203
|
};
|
|
204
204
|
inner: {
|
|
205
|
-
[key: string]: string | number | import("react-native").OpaqueColorValue | import("react-native").Animated.AnimatedNode | readonly import("react-native").BoxShadowValue[] | readonly import("react-native").FilterFunction[] | readonly import("react-native").
|
|
205
|
+
[key: string]: string | number | import("react-native").OpaqueColorValue | import("react-native").Animated.AnimatedNode | readonly import("react-native").BoxShadowValue[] | readonly import("react-native").FilterFunction[] | readonly import("react-native").BackgroundImageValue[] | readonly import("react-native").BackgroundSizeValue[] | readonly import("react-native").BackgroundPositionValue[] | readonly import("react-native").BackgroundRepeatValue[] | Readonly<{
|
|
206
206
|
width: number;
|
|
207
207
|
height: number;
|
|
208
208
|
}> | readonly (({
|
package/ios/RNBottomSheet.mm
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
#import "RNBottomSheetStateChangedEvent.h"
|
|
3
3
|
#import "RNBottomSheetOffsetChangedEvent.h"
|
|
4
4
|
|
|
5
|
+
#import "RNBottomSheetContentView.h"
|
|
6
|
+
|
|
5
7
|
#import <react/renderer/components/bottomsheet/ComponentDescriptors.h>
|
|
6
8
|
#import <react/renderer/components/bottomsheet/EventEmitters.h>
|
|
7
9
|
#import <react/renderer/components/bottomsheet/Props.h>
|
|
@@ -58,6 +60,7 @@ using namespace facebook::react;
|
|
|
58
60
|
__weak UIView *_rootView;
|
|
59
61
|
BOOL _isInitialRender;
|
|
60
62
|
__weak UIView *_reactRootView;
|
|
63
|
+
CGFloat _layoutContentTop; // 子 View 的布局 origin.y,用于 contentOffset = 实际 top - 布局 top
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
// Needed because of this: https://github.com/facebook/react-native/pull/37274
|
|
@@ -84,6 +87,7 @@ using namespace facebook::react;
|
|
|
84
87
|
_status = BottomSheetStatus::Collapsed;
|
|
85
88
|
_finalStatus = BottomSheetStatus::Collapsed;
|
|
86
89
|
_isInitialRender = YES;
|
|
90
|
+
_layoutContentTop = NAN;
|
|
87
91
|
}
|
|
88
92
|
return self;
|
|
89
93
|
}
|
|
@@ -228,7 +232,7 @@ using namespace facebook::react;
|
|
|
228
232
|
|
|
229
233
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
230
234
|
if (self.finalStatus == BottomSheetStatus::Expanded && self->_isInitialRender) {
|
|
231
|
-
[self settleToStatus:self.finalStatus withFling:
|
|
235
|
+
[self settleToStatus:self.finalStatus withFling:YES];
|
|
232
236
|
}
|
|
233
237
|
|
|
234
238
|
self->_isInitialRender = NO;
|
|
@@ -238,6 +242,18 @@ using namespace facebook::react;
|
|
|
238
242
|
- (void)layoutChild {
|
|
239
243
|
if (!CGRectEqualToRect(self.child.frame, CGRectZero) && !CGRectEqualToRect(self.frame, CGRectZero)) {
|
|
240
244
|
[self calculateOffset];
|
|
245
|
+
// 仅当当前 frame.origin.y 不是“本轮要设的目标”时才视为布局结果并捕获,避免初始 collapsed + peekHeight 0 时误把已是 maxY 的 frame 当布局
|
|
246
|
+
if (isnan(_layoutContentTop)) {
|
|
247
|
+
CGFloat currentY = self.child.frame.origin.y;
|
|
248
|
+
CGFloat targetY = (self.status == BottomSheetStatus::Collapsed) ? self.maxY
|
|
249
|
+
: (self.status == BottomSheetStatus::Expanded) ? self.minY
|
|
250
|
+
: (CGFloat)self.frame.size.height;
|
|
251
|
+
if (fabs(currentY - targetY) > 0.5) {
|
|
252
|
+
_layoutContentTop = currentY;
|
|
253
|
+
} else {
|
|
254
|
+
_layoutContentTop = self.minY; // 无法区分时假定布局在 minY(展开位)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
241
257
|
if (self.status == BottomSheetStatus::Collapsed) {
|
|
242
258
|
self.child.frame = CGRectOffset(self.child.frame, 0, self.maxY - self.child.frame.origin.y);
|
|
243
259
|
} else if (self.status == BottomSheetStatus::Expanded) {
|
|
@@ -461,6 +477,11 @@ using namespace facebook::react;
|
|
|
461
477
|
if (top < 0 || self.maxY == 0) {
|
|
462
478
|
return;
|
|
463
479
|
}
|
|
480
|
+
// 传的是「实际 top - 布局 top」的差值,供 getContentOriginOffset 做 hit-test 校正
|
|
481
|
+
if ([self.child respondsToSelector:@selector(updateContentOffset:)]) {
|
|
482
|
+
CGFloat offsetY = top - _layoutContentTop;
|
|
483
|
+
[(id)self.child updateContentOffset:offsetY];
|
|
484
|
+
}
|
|
464
485
|
|
|
465
486
|
CGFloat progress = fmin((top - self.minY) * 1.0f / (self.maxY - self.minY), 1);
|
|
466
487
|
BottomSheetEventEmitter::OnSlide payload = BottomSheetEventEmitter::OnSlide{
|
|
@@ -509,7 +530,7 @@ using namespace facebook::react;
|
|
|
509
530
|
}
|
|
510
531
|
|
|
511
532
|
- (void)stopWatchBottomSheetTransition {
|
|
512
|
-
if(_displayLink){
|
|
533
|
+
if (_displayLink) {
|
|
513
534
|
[_displayLink invalidate];
|
|
514
535
|
_displayLink = nil;
|
|
515
536
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#import "RNBottomSheetContentView.h"
|
|
2
|
+
|
|
3
|
+
#import <react/renderer/components/bottomsheet/BottomSheetContentViewComponentDescriptor.h>
|
|
4
|
+
#import <react/renderer/components/bottomsheet/BottomSheetContentViewShadowNode.h>
|
|
5
|
+
#import <react/renderer/components/bottomsheet/EventEmitters.h>
|
|
6
|
+
#import <react/renderer/components/bottomsheet/Props.h>
|
|
7
|
+
#import <react/renderer/components/bottomsheet/RCTComponentViewHelpers.h>
|
|
8
|
+
|
|
9
|
+
using namespace facebook::react;
|
|
10
|
+
|
|
11
|
+
@implementation RNBottomSheetContentView {
|
|
12
|
+
std::shared_ptr<const BottomSheetContentViewShadowNode::ConcreteState> _state;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
+ (void)load {
|
|
16
|
+
[super load];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider {
|
|
20
|
+
return concreteComponentDescriptorProvider<BottomSheetContentViewComponentDescriptor>();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
- (instancetype)initWithFrame:(CGRect)frame {
|
|
24
|
+
if (self = [super initWithFrame:frame]) {
|
|
25
|
+
static const auto defaultProps = std::make_shared<const BottomSheetContentViewProps>();
|
|
26
|
+
_props = defaultProps;
|
|
27
|
+
}
|
|
28
|
+
return self;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
- (void)updateState:(const facebook::react::State::Shared &)state oldState:(const facebook::react::State::Shared &)oldState {
|
|
32
|
+
_state = std::static_pointer_cast<const BottomSheetContentViewShadowNode::ConcreteState>(state);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
- (void)updateContentOffset:(CGFloat)contentOffset {
|
|
36
|
+
if (!_state) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
_state->updateState(
|
|
40
|
+
[contentOffset](const BottomSheetContentViewShadowNode::ConcreteState::Data &oldData) -> BottomSheetContentViewShadowNode::ConcreteState::SharedData {
|
|
41
|
+
auto newData = oldData;
|
|
42
|
+
newData.contentOffset = static_cast<double>(contentOffset);
|
|
43
|
+
return std::make_shared<BottomSheetContentViewShadowNode::ConcreteState::Data>(newData);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@end
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdcx/bottom-sheet",
|
|
3
3
|
"description": "A react-native BottomSheet component.",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.6",
|
|
5
5
|
"main": "./dist/index",
|
|
6
6
|
"module": "./dist/index",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
},
|
|
49
49
|
"ios": {
|
|
50
50
|
"componentProvider": {
|
|
51
|
-
"BottomSheet": "RNBottomSheet"
|
|
51
|
+
"BottomSheet": "RNBottomSheet",
|
|
52
|
+
"BottomSheetContentView": "RNBottomSheetContentView"
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
}
|
package/react-native.config.js
CHANGED
|
@@ -3,7 +3,8 @@ module.exports = {
|
|
|
3
3
|
platforms: {
|
|
4
4
|
android: {
|
|
5
5
|
libraryName: 'bottomsheet',
|
|
6
|
-
componentDescriptors: ['
|
|
6
|
+
componentDescriptors: ['BottomSheetContentViewComponentDescriptor'],
|
|
7
|
+
cmakeListsPath: 'src/main/jni/CMakeLists.txt',
|
|
7
8
|
},
|
|
8
9
|
},
|
|
9
10
|
},
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HostComponent, ViewProps } from 'react-native';
|
|
2
|
+
import { codegenNativeComponent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export interface NativeProps extends ViewProps {}
|
|
5
|
+
|
|
6
|
+
export default codegenNativeComponent<NativeProps>('BottomSheetContentView', {
|
|
7
|
+
interfaceOnly: true,
|
|
8
|
+
}) as HostComponent<NativeProps>;
|
package/src/index.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { NativeSyntheticEvent, StyleSheet,
|
|
2
|
+
import { NativeSyntheticEvent, StyleSheet, ViewProps } from 'react-native';
|
|
3
3
|
import splitLayoutProps from './splitLayoutProps';
|
|
4
4
|
import BottomSheetNativeComponent from './BottomSheetNativeComponent';
|
|
5
|
+
import BottomSheetContentViewNativeComponent from './BottomSheetContentViewNativeComponent';
|
|
5
6
|
import type { OnStateChangedEventPayload, OnSlideEventPayload } from './BottomSheetNativeComponent';
|
|
6
7
|
|
|
7
8
|
export type BottomSheetState = 'collapsed' | 'expanded' | 'hidden';
|
|
@@ -38,7 +39,7 @@ function BottomSheet(props: BottomSheetProps) {
|
|
|
38
39
|
status={state}
|
|
39
40
|
{...rest}
|
|
40
41
|
>
|
|
41
|
-
<
|
|
42
|
+
<BottomSheetContentViewNativeComponent
|
|
42
43
|
style={[
|
|
43
44
|
fitToContents ? styles.fitToContents : StyleSheet.absoluteFill,
|
|
44
45
|
inner,
|
|
@@ -47,7 +48,7 @@ function BottomSheet(props: BottomSheetProps) {
|
|
|
47
48
|
collapsable={false}
|
|
48
49
|
>
|
|
49
50
|
{children}
|
|
50
|
-
</
|
|
51
|
+
</BottomSheetContentViewNativeComponent>
|
|
51
52
|
</BottomSheetNativeComponent>
|
|
52
53
|
);
|
|
53
54
|
}
|