Skip to content

Commit 28d2c18

Browse files
authored
feat: add initialIndex & onMount props (#30)
* chore: upgrade deps * refactor: rename types file * feat(ios): add `initialIndex` prop * feat(ios): add `onLoad` * feat: add maps demo * docs: update docs * chore: upgrade docs * feat(android): implement `initialIndex` & `onLoad` * refactor: rename to `onReady` * fix: fix size change issue * refactor: rename event * feat(ios): add `animateOnMount` * feat(android): implement `initialIndexAnimated` * chore: example deps * refactor: files * chore: example deps * docs: add `initialIndexAnimated` prop doc * docs: preview
1 parent d30b873 commit 28d2c18

33 files changed

+1181
-553
lines changed

.yarnrc.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@ nmHoistingLimits: workspaces
33
nodeLinker: node-modules
44

55
plugins:
6-
spec: "@yarnpkg/plugin-interactive-tools"
7-
spec: "@yarnpkg/plugin-workspace-tools"
6+
spec: "@yarnpkg/plugin-workspace-tools"

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77
The true native bottom sheet experience for your React Native Apps. 💩
88

9-
<img alt="React Native True Sheet" src="docs/static/img/preview.gif" width="600px" />
9+
<img alt="React Native True Sheet - IOS" src="docs/static/img/preview.gif" width="300" height="600" />
10+
<img alt="React Native True Sheet - Android" src="docs/static/img/preview-2.gif" width="300" height="600" />
1011

1112
## Features
1213

android/src/main/java/com/lodev09/truesheet/TrueSheetDialog.kt

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
1919
BottomSheetDialog(reactContext) {
2020

2121
private var keyboardManager = KeyboardManager(reactContext)
22+
private var sheetView: ViewGroup
23+
private var windowAnimation: Int = 0
2224

2325
/**
2426
* Specify whether the sheet background is dimmed.
@@ -53,19 +55,20 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
5355

5456
var sizes: Array<Any> = arrayOf("medium", "large")
5557

56-
private var sheetView: ViewGroup
57-
5858
init {
5959
setContentView(rootSheetView)
6060
sheetView = rootSheetView.parent as ViewGroup
6161
sheetView.setBackgroundColor(Color.TRANSPARENT)
6262

63-
// Setup window params to adjust layout based on Keyboard state.
63+
// Setup window params to adjust layout based on Keyboard state
6464
window?.apply {
6565
// SOFT_INPUT_ADJUST_RESIZE to resize the sheet above the keyboard
6666
setSoftInputMode(
6767
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
6868
)
69+
70+
// Store current windowAnimation value to toggle later
71+
windowAnimation = attributes.windowAnimations
6972
}
7073

7174
// Update the usable sheet height
@@ -107,18 +110,29 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
107110
}
108111
}
109112

113+
fun resetAnimation() {
114+
window?.apply {
115+
setWindowAnimations(windowAnimation)
116+
}
117+
}
118+
110119
/**
111120
* Present the sheet.
112121
*/
113-
fun present(sizeIndex: Int) {
122+
fun present(sizeIndex: Int, animated: Boolean = true) {
114123
setupDimmedBackground(sizeIndex)
115124
if (isShowing) {
116125
setStateForSizeIndex(sizeIndex)
117126
} else {
118127
configure()
119128
setStateForSizeIndex(sizeIndex)
120129

121-
this.show()
130+
if (!animated) {
131+
// Disable animation
132+
window?.setWindowAnimations(0)
133+
}
134+
135+
show()
122136
}
123137
}
124138

@@ -178,10 +192,7 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
178192
else -> (maxScreenHeight * 0.5).toInt()
179193
}
180194

181-
return when (maxSheetHeight) {
182-
null -> height
183-
else -> minOf(height, maxSheetHeight ?: maxScreenHeight)
184-
}
195+
return maxSheetHeight?.let { minOf(height, it, maxScreenHeight) } ?: minOf(height, maxScreenHeight)
185196
}
186197

187198
/**
@@ -216,7 +227,7 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
216227
* Also update footer's Y position.
217228
*/
218229
fun registerKeyboardManager() {
219-
keyboardManager.registerKeyboardListener(object : KeyboardManager.OnKeyboardListener {
230+
keyboardManager.registerKeyboardListener(object : KeyboardManager.OnKeyboardChangeListener {
220231
override fun onKeyboardStateChange(isVisible: Boolean, visibleHeight: Int?) {
221232
maxScreenHeight = when (isVisible) {
222233
true -> visibleHeight ?: 0
@@ -228,6 +239,10 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
228239
})
229240
}
230241

242+
fun setOnSizeChangeListener(listener: RootSheetView.OnSizeChangeListener) {
243+
rootSheetView.setOnSizeChangeListener(listener)
244+
}
245+
231246
/**
232247
* Remove keyboard listener.
233248
*/
@@ -263,7 +278,8 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
263278
isFitToContents = false
264279

265280
setPeekHeight(getSizeHeight(sizes[0]), isShowing)
266-
halfExpandedRatio = getSizeHeight(sizes[1]).toFloat() / maxScreenHeight.toFloat()
281+
282+
halfExpandedRatio = minOf(getSizeHeight(sizes[1]).toFloat() / maxScreenHeight.toFloat(), 1.0f)
267283
maxHeight = getSizeHeight(sizes[2])
268284
}
269285
}

android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ import com.facebook.react.uimanager.ThemedReactContext
1111
import com.facebook.react.uimanager.UIManagerHelper
1212
import com.facebook.react.uimanager.events.EventDispatcher
1313
import com.google.android.material.bottomsheet.BottomSheetBehavior
14-
import com.lodev09.truesheet.core.DismissEvent
15-
import com.lodev09.truesheet.core.PresentEvent
1614
import com.lodev09.truesheet.core.RootSheetView
17-
import com.lodev09.truesheet.core.SizeChangeEvent
15+
import com.lodev09.truesheet.events.DismissEvent
16+
import com.lodev09.truesheet.events.MountEvent
17+
import com.lodev09.truesheet.events.PresentEvent
18+
import com.lodev09.truesheet.events.SizeChangeEvent
1819

1920
class TrueSheetView(context: Context) :
2021
ViewGroup(context),
@@ -27,6 +28,9 @@ class TrueSheetView(context: Context) :
2728
private val surfaceId: Int
2829
get() = UIManagerHelper.getSurfaceId(this)
2930

31+
var initialIndex: Int = -1
32+
var initialIndexAnimated: Boolean = true
33+
3034
/**
3135
* Current activeIndex.
3236
*/
@@ -52,11 +56,6 @@ class TrueSheetView(context: Context) :
5256
*/
5357
private val rootSheetView: RootSheetView
5458

55-
/**
56-
* 2nd child of the container view.
57-
*/
58-
private var footerView: ViewGroup? = null
59-
6059
init {
6160
reactContext.addLifecycleEventListener(this)
6261
eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
@@ -77,13 +76,16 @@ class TrueSheetView(context: Context) :
7776
positionFooter()
7877
}
7978

79+
// Re-enable animation
80+
resetAnimation()
81+
8082
// Resolve the present promise
8183
presentPromise?.let { promise ->
8284
promise()
8385
presentPromise = null
8486
}
8587

86-
// dispatch onPresent event
88+
// Dispatch onPresent event
8789
eventDispatcher?.dispatchEvent(PresentEvent(surfaceId, id, sheetDialog.getSizeInfoForIndex(currentSizeIndex)))
8890
}
8991

@@ -97,10 +99,17 @@ class TrueSheetView(context: Context) :
9799
dismissPromise = null
98100
}
99101

100-
// dispatch onDismiss event
102+
// Dispatch onDismiss event
101103
eventDispatcher?.dispatchEvent(DismissEvent(surfaceId, id))
102104
}
103105

106+
// Configure when showing and size changed
107+
setOnSizeChangeListener(object : RootSheetView.OnSizeChangeListener {
108+
override fun onSizeChange(width: Int, height: Int) {
109+
maxScreenHeight = height
110+
}
111+
})
112+
104113
// Configure sheet behavior events
105114
behavior.addBottomSheetCallback(
106115
object : BottomSheetBehavior.BottomSheetCallback() {
@@ -132,7 +141,7 @@ class TrueSheetView(context: Context) :
132141
currentSizeIndex = sizeInfo.index
133142
setupDimmedBackground(sizeInfo.index)
134143

135-
// dispatch onSizeChange event
144+
// Dispatch onSizeChange event
136145
eventDispatcher?.dispatchEvent(SizeChangeEvent(surfaceId, id, sizeInfo))
137146
}
138147
}
@@ -164,13 +173,28 @@ class TrueSheetView(context: Context) :
164173
visibility = GONE
165174

166175
(child as ViewGroup).let {
167-
// Container View's first child is the Content View
168-
footerView = it.getChildAt(1) as ViewGroup
169-
170-
sheetDialog.footerView = footerView
171-
172176
// rootView's first child is the Container View
173177
rootSheetView.addView(it, index)
178+
179+
// Initialize content
180+
UiThreadUtil.runOnUiThread {
181+
// 1st child is the content view
182+
val contentView = it.getChildAt(0) as ViewGroup
183+
setContentHeight(contentView.height)
184+
185+
// 2nd child is the footer view
186+
val footerView = it.getChildAt(1) as ViewGroup
187+
sheetDialog.footerView = footerView
188+
setFooterHeight(footerView.height)
189+
190+
if (initialIndex >= 0) {
191+
currentSizeIndex = initialIndex
192+
sheetDialog.present(initialIndex, initialIndexAnimated)
193+
}
194+
195+
// Dispatch onMount event
196+
eventDispatcher?.dispatchEvent(MountEvent(surfaceId, id))
197+
}
174198
}
175199
}
176200

@@ -224,28 +248,38 @@ class TrueSheetView(context: Context) :
224248
}
225249

226250
fun setMaxHeight(height: Int) {
251+
if (sheetDialog.maxSheetHeight == height) return
252+
227253
sheetDialog.maxSheetHeight = height
228254
configureIfShowing()
229255
}
230256

231257
fun setContentHeight(height: Int) {
258+
if (sheetDialog.contentHeight == height) return
259+
232260
sheetDialog.contentHeight = height
233261
configureIfShowing()
234262
}
235263

236264
fun setFooterHeight(height: Int) {
265+
if (sheetDialog.footerHeight == height) return
266+
237267
sheetDialog.footerHeight = height
238268
configureIfShowing()
239269
}
240270

241271
fun setDimmed(dimmed: Boolean) {
272+
if (sheetDialog.dimmed == dimmed) return
273+
242274
sheetDialog.dimmed = dimmed
243275
if (sheetDialog.isShowing) {
244276
sheetDialog.setupDimmedBackground(currentSizeIndex)
245277
}
246278
}
247279

248280
fun setDimmedIndex(index: Int) {
281+
if (sheetDialog.dimmedIndex == index) return
282+
249283
sheetDialog.dimmedIndex = index
250284
if (sheetDialog.isShowing) {
251285
sheetDialog.setupDimmedBackground(currentSizeIndex)

android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import com.facebook.react.common.MapBuilder
77
import com.facebook.react.uimanager.ThemedReactContext
88
import com.facebook.react.uimanager.ViewGroupManager
99
import com.facebook.react.uimanager.annotations.ReactProp
10-
import com.lodev09.truesheet.core.DismissEvent
11-
import com.lodev09.truesheet.core.PresentEvent
12-
import com.lodev09.truesheet.core.SizeChangeEvent
1310
import com.lodev09.truesheet.core.Utils
11+
import com.lodev09.truesheet.events.DismissEvent
12+
import com.lodev09.truesheet.events.MountEvent
13+
import com.lodev09.truesheet.events.PresentEvent
14+
import com.lodev09.truesheet.events.SizeChangeEvent
1415

1516
class TrueSheetViewManager : ViewGroupManager<TrueSheetView>() {
1617
override fun getName() = TAG
@@ -24,6 +25,7 @@ class TrueSheetViewManager : ViewGroupManager<TrueSheetView>() {
2425

2526
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any>? =
2627
MapBuilder.builder<String, Any>()
28+
.put(MountEvent.EVENT_NAME, MapBuilder.of("registrationName", "onMount"))
2729
.put(PresentEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPresent"))
2830
.put(DismissEvent.EVENT_NAME, MapBuilder.of("registrationName", "onDismiss"))
2931
.put(SizeChangeEvent.EVENT_NAME, MapBuilder.of("registrationName", "onSizeChange"))
@@ -44,6 +46,16 @@ class TrueSheetViewManager : ViewGroupManager<TrueSheetView>() {
4446
view.setDimmed(dimmed)
4547
}
4648

49+
@ReactProp(name = "initialIndex")
50+
fun setInitialIndex(view: TrueSheetView, index: Int) {
51+
view.initialIndex = index
52+
}
53+
54+
@ReactProp(name = "initialIndexAnimated")
55+
fun setInitialIndexAnimated(view: TrueSheetView, animate: Boolean) {
56+
view.initialIndexAnimated = animate
57+
}
58+
4759
@ReactProp(name = "dimmedIndex")
4860
fun setDimmedIndex(view: TrueSheetView, index: Int) {
4961
view.setDimmedIndex(index)

android/src/main/java/com/lodev09/truesheet/core/Events.kt

Lines changed: 0 additions & 51 deletions
This file was deleted.

android/src/main/java/com/lodev09/truesheet/core/KeyboardManager.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import android.view.inputmethod.InputMethodManager
77
import com.facebook.react.bridge.ReactContext
88

99
class KeyboardManager(reactContext: ReactContext) {
10-
interface OnKeyboardListener {
10+
interface OnKeyboardChangeListener {
1111
fun onKeyboardStateChange(isVisible: Boolean, visibleHeight: Int?)
1212
}
1313

@@ -20,7 +20,7 @@ class KeyboardManager(reactContext: ReactContext) {
2020
contentView = activity?.findViewById(android.R.id.content)
2121
}
2222

23-
fun registerKeyboardListener(listener: OnKeyboardListener?) {
23+
fun registerKeyboardListener(listener: OnKeyboardChangeListener?) {
2424
contentView?.apply {
2525
unregisterKeyboardListener()
2626

0 commit comments

Comments
 (0)