@lodev09/react-native-true-sheet 3.9.6 → 3.9.8
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/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +5 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +53 -47
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +7 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +6 -9
- package/ios/TrueSheetContainerView.h +1 -8
- package/ios/TrueSheetContainerView.mm +2 -2
- package/ios/TrueSheetContentView.h +1 -1
- package/ios/TrueSheetContentView.mm +32 -30
- package/ios/TrueSheetView.mm +5 -0
- package/ios/TrueSheetViewController.mm +25 -0
- package/ios/core/TrueSheetGrabberView.h +3 -0
- package/ios/core/TrueSheetGrabberView.mm +11 -1
- package/ios/core/TrueSheetKeyboardObserver.h +1 -0
- package/ios/core/TrueSheetKeyboardObserver.mm +7 -0
- package/package.json +3 -5
|
@@ -11,6 +11,7 @@ interface TrueSheetContainerViewDelegate {
|
|
|
11
11
|
val eventDispatcher: EventDispatcher?
|
|
12
12
|
fun containerViewContentDidChangeSize(width: Int, height: Int)
|
|
13
13
|
fun containerViewContentDidScroll()
|
|
14
|
+
fun containerViewScrollViewDidChange()
|
|
14
15
|
fun containerViewHeaderDidChangeSize(width: Int, height: Int)
|
|
15
16
|
fun containerViewFooterDidChangeSize(width: Int, height: Int)
|
|
16
17
|
}
|
|
@@ -124,6 +125,10 @@ class TrueSheetContainerView(reactContext: ThemedReactContext) :
|
|
|
124
125
|
delegate?.containerViewContentDidScroll()
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
override fun contentViewScrollViewDidChange() {
|
|
129
|
+
delegate?.containerViewScrollViewDidChange()
|
|
130
|
+
}
|
|
131
|
+
|
|
127
132
|
override fun headerViewDidChangeSize(width: Int, height: Int) {
|
|
128
133
|
headerHeight = height
|
|
129
134
|
delegate?.containerViewHeaderDidChangeSize(width, height)
|
|
@@ -18,6 +18,7 @@ import com.lodev09.truesheet.utils.isDescendantOf
|
|
|
18
18
|
interface TrueSheetContentViewDelegate {
|
|
19
19
|
fun contentViewDidChangeSize(width: Int, height: Int)
|
|
20
20
|
fun contentViewDidScroll()
|
|
21
|
+
fun contentViewScrollViewDidChange()
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -32,7 +33,6 @@ class TrueSheetContentView(private val reactContext: ThemedReactContext) : React
|
|
|
32
33
|
private var lastHeight = 0
|
|
33
34
|
|
|
34
35
|
private var pinnedScrollView: ScrollView? = null
|
|
35
|
-
private var cachedScrollView: ScrollView? = null
|
|
36
36
|
private var originalScrollViewPaddingBottom: Int = 0
|
|
37
37
|
private var bottomInset: Int = 0
|
|
38
38
|
|
|
@@ -45,6 +45,22 @@ class TrueSheetContentView(private val reactContext: ThemedReactContext) : React
|
|
|
45
45
|
keyboardScrollOffset = value?.getDouble("keyboardScrollOffset")?.toFloat()?.dpToPx() ?: 0f
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
override fun addView(child: View?, index: Int) {
|
|
49
|
+
super.addView(child, index)
|
|
50
|
+
checkScrollViewChanged()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override fun removeViewAt(index: Int) {
|
|
54
|
+
super.removeViewAt(index)
|
|
55
|
+
checkScrollViewChanged()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private fun checkScrollViewChanged() {
|
|
59
|
+
if (pinnedScrollView == null || pinnedScrollView?.isDescendantOf(this) == false) {
|
|
60
|
+
delegate?.contentViewScrollViewDidChange()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
48
64
|
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
|
49
65
|
super.onSizeChanged(w, h, oldw, oldh)
|
|
50
66
|
|
|
@@ -61,65 +77,63 @@ class TrueSheetContentView(private val reactContext: ThemedReactContext) : React
|
|
|
61
77
|
return
|
|
62
78
|
}
|
|
63
79
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
80
|
+
// Check if pinned scroll view is still valid (still in view hierarchy)
|
|
81
|
+
if (pinnedScrollView != null && pinnedScrollView?.isDescendantOf(this) == false) {
|
|
82
|
+
clearScrollable()
|
|
83
|
+
}
|
|
67
84
|
|
|
68
|
-
|
|
69
|
-
|
|
85
|
+
// Already set up with same inset and valid scroll view
|
|
86
|
+
if (pinnedScrollView != null && this.bottomInset == bottomInset) {
|
|
87
|
+
return
|
|
88
|
+
}
|
|
70
89
|
|
|
71
|
-
|
|
72
|
-
// Clean up previous scroll view
|
|
73
|
-
pinnedScrollView?.setOnScrollChangeListener(null as View.OnScrollChangeListener?)
|
|
74
|
-
pinnedScrollView?.setPadding(
|
|
75
|
-
pinnedScrollView!!.paddingLeft,
|
|
76
|
-
pinnedScrollView!!.paddingTop,
|
|
77
|
-
pinnedScrollView!!.paddingRight,
|
|
78
|
-
originalScrollViewPaddingBottom
|
|
79
|
-
)
|
|
90
|
+
val scrollView = findScrollView(this) ?: return
|
|
80
91
|
|
|
92
|
+
// Only capture originals on first pin
|
|
93
|
+
if (pinnedScrollView == null) {
|
|
94
|
+
originalScrollViewPaddingBottom = scrollView.paddingBottom
|
|
81
95
|
pinnedScrollView = scrollView
|
|
82
|
-
originalScrollViewPaddingBottom = scrollView?.paddingBottom ?: 0
|
|
83
96
|
|
|
84
|
-
scrollView
|
|
97
|
+
scrollView.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
|
85
98
|
if (scrollY != oldScrollY) {
|
|
86
99
|
delegate?.contentViewDidScroll()
|
|
87
100
|
}
|
|
88
101
|
}
|
|
89
102
|
}
|
|
90
103
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
)
|
|
104
|
+
this.bottomInset = bottomInset
|
|
105
|
+
|
|
106
|
+
setScrollViewPaddingBottom(originalScrollViewPaddingBottom + bottomInset)
|
|
107
|
+
|
|
108
|
+
// If keyboard is currently showing, re-apply the keyboard inset to the new ScrollView
|
|
109
|
+
val keyboardHeight = keyboardObserver?.currentHeight ?: 0
|
|
110
|
+
if (keyboardHeight > 0) {
|
|
111
|
+
setScrollViewPaddingBottom(originalScrollViewPaddingBottom + keyboardHeight)
|
|
99
112
|
}
|
|
100
113
|
}
|
|
101
114
|
|
|
115
|
+
private fun setScrollViewPaddingBottom(paddingBottom: Int) {
|
|
116
|
+
val scrollView = pinnedScrollView ?: return
|
|
117
|
+
scrollView.clipToPadding = false
|
|
118
|
+
scrollView.setPadding(
|
|
119
|
+
scrollView.paddingLeft,
|
|
120
|
+
scrollView.paddingTop,
|
|
121
|
+
scrollView.paddingRight,
|
|
122
|
+
paddingBottom
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
102
126
|
fun clearScrollable() {
|
|
103
127
|
pinnedScrollView?.setOnScrollChangeListener(null as View.OnScrollChangeListener?)
|
|
104
|
-
|
|
105
|
-
pinnedScrollView!!.paddingLeft,
|
|
106
|
-
pinnedScrollView!!.paddingTop,
|
|
107
|
-
pinnedScrollView!!.paddingRight,
|
|
108
|
-
originalScrollViewPaddingBottom
|
|
109
|
-
)
|
|
128
|
+
setScrollViewPaddingBottom(originalScrollViewPaddingBottom)
|
|
110
129
|
pinnedScrollView = null
|
|
111
|
-
cachedScrollView = null
|
|
112
130
|
originalScrollViewPaddingBottom = 0
|
|
113
131
|
bottomInset = 0
|
|
114
132
|
}
|
|
115
133
|
|
|
116
134
|
fun findScrollView(): ScrollView? {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (it.isAttachedToWindow && it.isDescendantOf(this)) return it
|
|
120
|
-
cachedScrollView = null
|
|
121
|
-
}
|
|
122
|
-
return findScrollView(this as View).also { cachedScrollView = it }
|
|
135
|
+
if (pinnedScrollView != null) return pinnedScrollView
|
|
136
|
+
return findScrollView(this as View)
|
|
123
137
|
}
|
|
124
138
|
|
|
125
139
|
private fun findScrollView(view: View): ScrollView? {
|
|
@@ -175,15 +189,7 @@ class TrueSheetContentView(private val reactContext: ThemedReactContext) : React
|
|
|
175
189
|
val scrollView = pinnedScrollView ?: return
|
|
176
190
|
|
|
177
191
|
val totalBottomInset = if (keyboardHeight > 0) keyboardHeight else bottomInset
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
scrollView.clipToPadding = false
|
|
181
|
-
scrollView.setPadding(
|
|
182
|
-
scrollView.paddingLeft,
|
|
183
|
-
scrollView.paddingTop,
|
|
184
|
-
scrollView.paddingRight,
|
|
185
|
-
newPaddingBottom
|
|
186
|
-
)
|
|
192
|
+
setScrollViewPaddingBottom(originalScrollViewPaddingBottom + totalBottomInset)
|
|
187
193
|
|
|
188
194
|
// Trigger a scroll to force update
|
|
189
195
|
scrollView.post {
|
|
@@ -592,6 +592,13 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
592
592
|
viewController.commitKeyboardDetent()
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
+
// When the ScrollView changes (e.g. conditional remount), re-pin the new ScrollView
|
|
596
|
+
// and request layout so BottomSheetBehavior re-discovers the nested scrolling child.
|
|
597
|
+
override fun containerViewScrollViewDidChange() {
|
|
598
|
+
setupScrollable()
|
|
599
|
+
viewController.sheetView?.requestLayout()
|
|
600
|
+
}
|
|
601
|
+
|
|
595
602
|
override fun containerViewHeaderDidChangeSize(width: Int, height: Int) {
|
|
596
603
|
updateSheetIfNeeded()
|
|
597
604
|
}
|
|
@@ -7,6 +7,7 @@ import android.view.MotionEvent
|
|
|
7
7
|
import android.view.ViewConfiguration
|
|
8
8
|
import android.widget.ScrollView
|
|
9
9
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
10
|
+
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
|
10
11
|
import com.facebook.react.uimanager.PointerEvents
|
|
11
12
|
import com.facebook.react.uimanager.ReactPointerEventsView
|
|
12
13
|
import com.lodev09.truesheet.utils.isDescendantOf
|
|
@@ -65,15 +66,10 @@ class TrueSheetCoordinatorLayout(context: Context) :
|
|
|
65
66
|
get() = PointerEvents.BOX_NONE
|
|
66
67
|
|
|
67
68
|
/**
|
|
68
|
-
* Clears stale `nestedScrollingChildRef` from BottomSheetBehavior
|
|
69
|
+
* Clears stale `nestedScrollingChildRef` from BottomSheetBehavior.
|
|
69
70
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* 1. A child sheet with a ScrollView is dismissed and its ScrollView returns to this hierarchy
|
|
73
|
-
* 2. A ScrollView is conditionally removed and re-added (e.g. React conditional rendering)
|
|
74
|
-
*
|
|
75
|
-
* When stale (GC'd target or view no longer in sheet), we clear the ref and request layout
|
|
76
|
-
* so `onLayoutChild` re-runs `findScrollingChild()` to discover the current ScrollView.
|
|
71
|
+
* The cached `nestedScrollingChildRef` can become stale when a child sheet
|
|
72
|
+
* with a ScrollView is dismissed and its ScrollView returns to this hierarchy.
|
|
77
73
|
*/
|
|
78
74
|
private fun clearStaleNestedScrollingChildRef() {
|
|
79
75
|
val sheet = delegate?.findSheetView() ?: return
|
|
@@ -86,7 +82,6 @@ class TrueSheetCoordinatorLayout(context: Context) :
|
|
|
86
82
|
val view = ref.get()
|
|
87
83
|
if (view == null || !view.isDescendantOf(sheet)) {
|
|
88
84
|
ref.clear()
|
|
89
|
-
sheet.requestLayout()
|
|
90
85
|
}
|
|
91
86
|
} catch (_: Exception) {}
|
|
92
87
|
}
|
|
@@ -104,7 +99,9 @@ class TrueSheetCoordinatorLayout(context: Context) :
|
|
|
104
99
|
}
|
|
105
100
|
|
|
106
101
|
val scrollView = delegate?.findScrollView()
|
|
102
|
+
val hasRefreshControl = scrollView?.parent is SwipeRefreshLayout
|
|
107
103
|
val cannotScroll = scrollView != null &&
|
|
104
|
+
!hasRefreshControl &&
|
|
108
105
|
scrollView.scrollY == 0 &&
|
|
109
106
|
!scrollView.canScrollVertically(1)
|
|
110
107
|
|
|
@@ -15,18 +15,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
15
15
|
|
|
16
16
|
@protocol TrueSheetContainerViewDelegate <NSObject>
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* Called when the container's content size changes
|
|
20
|
-
* @param newSize The new size of the content
|
|
21
|
-
*/
|
|
22
18
|
- (void)containerViewContentDidChangeSize:(CGSize)newSize;
|
|
19
|
+
- (void)containerViewScrollViewDidChange;
|
|
23
20
|
|
|
24
21
|
@optional
|
|
25
22
|
|
|
26
|
-
/**
|
|
27
|
-
* Called when the header size changes
|
|
28
|
-
* @param newSize The new size of the header
|
|
29
|
-
*/
|
|
30
23
|
- (void)containerViewHeaderDidChangeSize:(CGSize)newSize;
|
|
31
24
|
|
|
32
25
|
@end
|
|
@@ -175,8 +175,8 @@ using namespace facebook::react;
|
|
|
175
175
|
[self.delegate containerViewContentDidChangeSize:newSize];
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
- (void)
|
|
179
|
-
[self
|
|
178
|
+
- (void)contentViewScrollViewDidChange {
|
|
179
|
+
[self.delegate containerViewScrollViewDidChange];
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
#pragma mark - TrueSheetHeaderViewDelegate
|
|
@@ -57,29 +57,42 @@ using namespace facebook::react;
|
|
|
57
57
|
|
|
58
58
|
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
|
|
59
59
|
[super mountChildComponentView:childComponentView index:index];
|
|
60
|
-
[self
|
|
60
|
+
[self checkScrollViewChanged];
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
|
|
64
64
|
[super unmountChildComponentView:childComponentView index:index];
|
|
65
|
-
[self
|
|
65
|
+
[self checkScrollViewChanged];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
- (void)checkScrollViewChanged {
|
|
69
|
+
if (!_pinnedScrollView || ![_pinnedScrollView isDescendantOfView:self]) {
|
|
70
|
+
[self.delegate contentViewScrollViewDidChange];
|
|
71
|
+
}
|
|
66
72
|
}
|
|
67
73
|
|
|
68
74
|
#pragma mark - Scrollable
|
|
69
75
|
|
|
76
|
+
- (void)setScrollViewContentInset:(CGFloat)contentBottom indicatorInset:(CGFloat)indicatorBottom {
|
|
77
|
+
if (!_pinnedScrollView)
|
|
78
|
+
return;
|
|
79
|
+
|
|
80
|
+
UIEdgeInsets contentInset = _pinnedScrollView.scrollView.contentInset;
|
|
81
|
+
contentInset.bottom = contentBottom;
|
|
82
|
+
_pinnedScrollView.scrollView.contentInset = contentInset;
|
|
83
|
+
|
|
84
|
+
UIEdgeInsets indicatorInsets = _pinnedScrollView.scrollView.verticalScrollIndicatorInsets;
|
|
85
|
+
indicatorInsets.bottom = indicatorBottom;
|
|
86
|
+
_pinnedScrollView.scrollView.verticalScrollIndicatorInsets = indicatorInsets;
|
|
87
|
+
}
|
|
88
|
+
|
|
70
89
|
- (void)clearScrollable {
|
|
71
90
|
if (_pinnedScrollView) {
|
|
72
91
|
CGRect frame = _pinnedScrollView.frame;
|
|
73
92
|
frame.size.height = _originalScrollViewHeight;
|
|
74
93
|
_pinnedScrollView.frame = frame;
|
|
75
94
|
|
|
76
|
-
|
|
77
|
-
contentInset.bottom = 0;
|
|
78
|
-
_pinnedScrollView.scrollView.contentInset = contentInset;
|
|
79
|
-
|
|
80
|
-
UIEdgeInsets indicatorInsets = _pinnedScrollView.scrollView.verticalScrollIndicatorInsets;
|
|
81
|
-
indicatorInsets.bottom = _originalIndicatorBottomInset;
|
|
82
|
-
_pinnedScrollView.scrollView.verticalScrollIndicatorInsets = indicatorInsets;
|
|
95
|
+
[self setScrollViewContentInset:0 indicatorInset:_originalIndicatorBottomInset];
|
|
83
96
|
}
|
|
84
97
|
_pinnedScrollView = nil;
|
|
85
98
|
_bottomInset = 0;
|
|
@@ -94,7 +107,6 @@ using namespace facebook::react;
|
|
|
94
107
|
}
|
|
95
108
|
|
|
96
109
|
// Check if pinned scroll view is still valid (still in view hierarchy)
|
|
97
|
-
// This handles the case where content changes and the old scroll view is unmounted
|
|
98
110
|
if (_pinnedScrollView && ![_pinnedScrollView isDescendantOfView:self]) {
|
|
99
111
|
[self clearScrollable];
|
|
100
112
|
}
|
|
@@ -120,13 +132,13 @@ using namespace facebook::react;
|
|
|
120
132
|
|
|
121
133
|
[self updateScrollViewHeight];
|
|
122
134
|
|
|
123
|
-
|
|
124
|
-
contentInset.bottom = bottomInset;
|
|
125
|
-
scrollView.scrollView.contentInset = contentInset;
|
|
135
|
+
[self setScrollViewContentInset:_bottomInset indicatorInset:_originalIndicatorBottomInset];
|
|
126
136
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
137
|
+
// If keyboard is currently showing, re-apply the keyboard inset to the new ScrollView
|
|
138
|
+
CGFloat keyboardHeight = _keyboardObserver ? _keyboardObserver.currentHeight : 0;
|
|
139
|
+
if (keyboardHeight > 0) {
|
|
140
|
+
[self setScrollViewContentInset:keyboardHeight indicatorInset:_originalIndicatorBottomInset + keyboardHeight];
|
|
141
|
+
}
|
|
130
142
|
}
|
|
131
143
|
|
|
132
144
|
- (void)updateScrollViewHeight {
|
|
@@ -202,13 +214,8 @@ using namespace facebook::react;
|
|
|
202
214
|
delay:0
|
|
203
215
|
options:curve | UIViewAnimationOptionBeginFromCurrentState
|
|
204
216
|
animations:^{
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
self->_pinnedScrollView.scrollView.contentInset = contentInset;
|
|
208
|
-
|
|
209
|
-
UIEdgeInsets indicatorInsets = self->_pinnedScrollView.scrollView.verticalScrollIndicatorInsets;
|
|
210
|
-
indicatorInsets.bottom = self->_originalIndicatorBottomInset + height;
|
|
211
|
-
self->_pinnedScrollView.scrollView.verticalScrollIndicatorInsets = indicatorInsets;
|
|
217
|
+
[self setScrollViewContentInset:height
|
|
218
|
+
indicatorInset:self->_originalIndicatorBottomInset + height];
|
|
212
219
|
|
|
213
220
|
if (firstResponder) {
|
|
214
221
|
CGRect responderFrame = [firstResponder convertRect:firstResponder.bounds
|
|
@@ -229,13 +236,8 @@ using namespace facebook::react;
|
|
|
229
236
|
delay:0
|
|
230
237
|
options:curve | UIViewAnimationOptionBeginFromCurrentState
|
|
231
238
|
animations:^{
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
self->_pinnedScrollView.scrollView.contentInset = contentInset;
|
|
235
|
-
|
|
236
|
-
UIEdgeInsets indicatorInsets = self->_pinnedScrollView.scrollView.verticalScrollIndicatorInsets;
|
|
237
|
-
indicatorInsets.bottom = self->_originalIndicatorBottomInset;
|
|
238
|
-
self->_pinnedScrollView.scrollView.verticalScrollIndicatorInsets = indicatorInsets;
|
|
239
|
+
[self setScrollViewContentInset:self->_bottomInset
|
|
240
|
+
indicatorInset:self->_originalIndicatorBottomInset];
|
|
239
241
|
}
|
|
240
242
|
completion:nil];
|
|
241
243
|
}
|
package/ios/TrueSheetView.mm
CHANGED
|
@@ -574,6 +574,11 @@ using namespace facebook::react;
|
|
|
574
574
|
[self setupSheetDetentsForSizeChange];
|
|
575
575
|
}
|
|
576
576
|
|
|
577
|
+
// When the ScrollView changes (e.g. conditional remount), re-pin the new ScrollView.
|
|
578
|
+
- (void)containerViewScrollViewDidChange {
|
|
579
|
+
[_containerView setupScrollable];
|
|
580
|
+
}
|
|
581
|
+
|
|
577
582
|
#pragma mark - TrueSheetViewControllerDelegate
|
|
578
583
|
|
|
579
584
|
- (void)viewControllerWillPresentAtIndex:(NSInteger)index position:(CGFloat)position detent:(CGFloat)detent {
|
|
@@ -743,10 +743,35 @@ using namespace facebook::react;
|
|
|
743
743
|
[_grabberView applyConfiguration];
|
|
744
744
|
_grabberView.hidden = !showGrabber;
|
|
745
745
|
|
|
746
|
+
__weak __typeof(self) weakSelf = self;
|
|
747
|
+
_grabberView.onTap = ^{
|
|
748
|
+
[weakSelf handleGrabberTap];
|
|
749
|
+
};
|
|
750
|
+
|
|
746
751
|
[self.view bringSubviewToFront:_grabberView];
|
|
747
752
|
} else {
|
|
748
753
|
self.sheet.prefersGrabberVisible = showGrabber;
|
|
749
754
|
_grabberView.hidden = YES;
|
|
755
|
+
_grabberView.onTap = nil;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
- (void)handleGrabberTap {
|
|
760
|
+
NSInteger detentCount = _detents.count;
|
|
761
|
+
if (detentCount == 0)
|
|
762
|
+
return;
|
|
763
|
+
|
|
764
|
+
NSInteger currentIndex = self.currentDetentIndex;
|
|
765
|
+
if (currentIndex < 0)
|
|
766
|
+
return;
|
|
767
|
+
|
|
768
|
+
NSInteger nextIndex = (currentIndex + 1) % detentCount;
|
|
769
|
+
if (nextIndex == 0 && detentCount == 1 && self.dismissible) {
|
|
770
|
+
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
|
|
771
|
+
} else {
|
|
772
|
+
[self.sheet animateChanges:^{
|
|
773
|
+
[self resizeToDetentIndex:nextIndex];
|
|
774
|
+
}];
|
|
750
775
|
}
|
|
751
776
|
}
|
|
752
777
|
|
|
@@ -34,6 +34,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
34
34
|
/// Whether the grabber color adapts to the background (default: YES)
|
|
35
35
|
@property (nonatomic, strong, nullable) NSNumber *adaptive;
|
|
36
36
|
|
|
37
|
+
/// Called when the grabber is tapped
|
|
38
|
+
@property (nonatomic, copy, nullable) void (^onTap)(void);
|
|
39
|
+
|
|
37
40
|
/// Adds the grabber view to a parent view with proper constraints
|
|
38
41
|
- (void)addToView:(UIView *)parentView;
|
|
39
42
|
|
|
@@ -51,9 +51,11 @@ static const CGFloat kDefaultGrabberTopMargin = 5.0;
|
|
|
51
51
|
#pragma mark - Setup
|
|
52
52
|
|
|
53
53
|
- (void)setupView {
|
|
54
|
-
self.userInteractionEnabled = NO;
|
|
55
54
|
self.clipsToBounds = YES;
|
|
56
55
|
|
|
56
|
+
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)];
|
|
57
|
+
[self addGestureRecognizer:tap];
|
|
58
|
+
|
|
57
59
|
_vibrancyView = [[UIVisualEffectView alloc] initWithEffect:nil];
|
|
58
60
|
_vibrancyView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
59
61
|
[self addSubview:_vibrancyView];
|
|
@@ -64,6 +66,14 @@ static const CGFloat kDefaultGrabberTopMargin = 5.0;
|
|
|
64
66
|
[_vibrancyView.contentView addSubview:_fillView];
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
#pragma mark - Actions
|
|
70
|
+
|
|
71
|
+
- (void)handleTap {
|
|
72
|
+
if (_onTap) {
|
|
73
|
+
_onTap();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
67
77
|
#pragma mark - Public
|
|
68
78
|
|
|
69
79
|
- (void)addToView:(UIView *)parentView {
|
|
@@ -24,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
24
24
|
@interface TrueSheetKeyboardObserver : NSObject
|
|
25
25
|
|
|
26
26
|
@property (nonatomic, weak, nullable) TrueSheetViewController *viewController;
|
|
27
|
+
@property (nonatomic, readonly) CGFloat currentHeight;
|
|
27
28
|
|
|
28
29
|
- (void)addDelegate:(id<TrueSheetKeyboardObserverDelegate>)delegate;
|
|
29
30
|
- (void)removeDelegate:(id<TrueSheetKeyboardObserverDelegate>)delegate;
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
@implementation TrueSheetKeyboardObserver {
|
|
16
16
|
NSHashTable<id<TrueSheetKeyboardObserverDelegate>> *_delegates;
|
|
17
|
+
CGFloat _currentHeight;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
- (CGFloat)currentHeight {
|
|
21
|
+
return _currentHeight;
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
- (instancetype)init {
|
|
@@ -76,6 +81,8 @@
|
|
|
76
81
|
CGRect keyboardFrameInWindow = [window convertRect:keyboardFrame fromWindow:nil];
|
|
77
82
|
CGFloat keyboardHeight = MAX(0, window.bounds.size.height - keyboardFrameInWindow.origin.y);
|
|
78
83
|
|
|
84
|
+
_currentHeight = keyboardHeight;
|
|
85
|
+
|
|
79
86
|
for (id<TrueSheetKeyboardObserverDelegate> delegate in _delegates) {
|
|
80
87
|
if (keyboardHeight > 0) {
|
|
81
88
|
[delegate keyboardWillShow:keyboardHeight duration:duration curve:curve];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lodev09/react-native-true-sheet",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.8",
|
|
4
4
|
"description": "The true native bottom sheet experience for your React Native Apps.",
|
|
5
5
|
"source": "./src/index.ts",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
@@ -185,10 +185,8 @@
|
|
|
185
185
|
"publish": false
|
|
186
186
|
},
|
|
187
187
|
"hooks": {
|
|
188
|
-
"before:init":
|
|
189
|
-
|
|
190
|
-
"yarn test"
|
|
191
|
-
]
|
|
188
|
+
"before:init": "yarn test",
|
|
189
|
+
"after:bump": "yarn tidy && sed -i '' 's/## Unreleased/## Unreleased\\n\\n## ${version}/' CHANGELOG.md"
|
|
192
190
|
},
|
|
193
191
|
"github": {
|
|
194
192
|
"release": true,
|