Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 35 additions & 3 deletions android/src/main/java/com/behavior/BottomSheetBehavior.java
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ void onLayout(@NonNull View bottomSheet) {}
@Nullable private ValueAnimator interpolatorAnimator;

private static final int DEF_STYLE_RES = R.style.Widget_Design_BottomSheet_Modal;
private static final int SHEET_DRAG_TOUCH_SLOP_MULTIPLIER = 2;

int expandedOffset;

Expand Down Expand Up @@ -304,6 +305,7 @@ void onLayout(@NonNull View bottomSheet) {}
private int lastNestedScrollDy;

private boolean nestedScrolled;
private int nestedScrollDragDy;

private float hideFriction = HIDE_FRICTION;

Expand Down Expand Up @@ -662,6 +664,7 @@ public boolean onInterceptTouchEvent(
}
if (!ignoreEvents
&& viewDragHelper != null
&& (action != MotionEvent.ACTION_MOVE || isPastSheetDragTouchSlop(event))
&& viewDragHelper.shouldInterceptTouchEvent(event)) {
return true;
}
Expand All @@ -675,7 +678,7 @@ public boolean onInterceptTouchEvent(
&& state != STATE_DRAGGING
&& (!parent.isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY()) || (initialY - event.getY() < 10 && !canVisuallyScrollUp(scroll)))
&& viewDragHelper != null
&& Math.abs(initialY - event.getY()) > viewDragHelper.getTouchSlop();
&& isPastSheetDragTouchSlop(event);
return iss;
}

Expand All @@ -689,7 +692,7 @@ public boolean onTouchEvent(
if (state == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) {
return true;
}
if (shouldHandleDraggingWithHelper()) {
if (shouldHandleDraggingWithHelper() && shouldForwardToDragHelper(event)) {
viewDragHelper.processTouchEvent(event);
}
// Record the velocity
Expand All @@ -703,7 +706,7 @@ public boolean onTouchEvent(
// The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it
// to capture the bottom sheet in case it is not captured and the touch slop is passed.
if (shouldHandleDraggingWithHelper() && action == MotionEvent.ACTION_MOVE && !ignoreEvents) {
if (Math.abs(initialY - event.getY()) > viewDragHelper.getTouchSlop()) {
if (isPastSheetDragTouchSlop(event)) {
viewDragHelper.captureChildView(child, event.getPointerId(event.getActionIndex()));
}
}
Expand All @@ -720,6 +723,7 @@ public boolean onStartNestedScroll(
int type) {
lastNestedScrollDy = 0;
nestedScrolled = false;
nestedScrollDragDy = 0;
return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}

Expand Down Expand Up @@ -761,6 +765,9 @@ public void onNestedPreScroll(
// Prevent dragging
return;
}
if (!isPastNestedScrollDragTouchSlop(physicalDy)) {
return;
}

consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -physicalDy);
Expand All @@ -773,6 +780,9 @@ public void onNestedPreScroll(
// Prevent dragging
return;
}
if (!isPastNestedScrollDragTouchSlop(physicalDy)) {
return;
}

consumed[1] = dy;
ViewCompat.offsetTopAndBottom(child, -physicalDy);
Expand Down Expand Up @@ -862,6 +872,7 @@ public void onStopNestedScroll(
}
startSettling(child, targetState, false);
nestedScrolled = false;
nestedScrollDragDy = 0;
}

@Override
Expand Down Expand Up @@ -1592,6 +1603,27 @@ private boolean shouldHandleDraggingWithHelper() {
return viewDragHelper != null && (draggable || state == STATE_DRAGGING);
}

private boolean shouldForwardToDragHelper(@NonNull MotionEvent event) {
return event.getActionMasked() != MotionEvent.ACTION_MOVE
|| state == STATE_DRAGGING
|| isPastSheetDragTouchSlop(event);
}

private boolean isPastSheetDragTouchSlop(@NonNull MotionEvent event) {
return viewDragHelper != null
&& Math.abs(initialY - event.getY()) >
viewDragHelper.getTouchSlop() * SHEET_DRAG_TOUCH_SLOP_MULTIPLIER;
}

private boolean isPastNestedScrollDragTouchSlop(int dy) {
if (state == STATE_DRAGGING || viewDragHelper == null) {
return true;
}
nestedScrollDragDy += dy;
return Math.abs(nestedScrollDragDy) >
viewDragHelper.getTouchSlop() * SHEET_DRAG_TOUCH_SLOP_MULTIPLIER;
}

private void createMaterialShapeDrawableIfNeeded(@NonNull Context context) {
if (shapeAppearanceModelDefault == null) {
return;
Expand Down
49 changes: 47 additions & 2 deletions android/src/main/java/com/sheet2/AppFittedSheet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ open class AppFittedSheet(context: Context) : ViewGroup(context), LifecycleEvent
private var stacked = true
private val fragmentTag = "CCBottomSheet-${System.currentTimeMillis()}"
var mHostView = DialogRootViewGroup(context)
private var inlineOverlayView: View? = null
private var dialogOverlayView: View? = null

var dismissable = true
set(value) {
Expand Down Expand Up @@ -108,6 +110,10 @@ open class AppFittedSheet(context: Context) : ViewGroup(context), LifecycleEvent
InlineSheetPresenter(this, mHostView)
}

init {
mHostView.onSheetLayoutChanged = { pushContentOriginOffset() }
}

var maxWidth: Float = 0F
set(value) {
field = value
Expand Down Expand Up @@ -197,6 +203,7 @@ open class AppFittedSheet(context: Context) : ViewGroup(context), LifecycleEvent
}
getCurrentActivity()?.supportFragmentManager?.let {
fragment.safeShow(it, fragmentTag)
fragment.setOverlayView(dialogOverlayView)
if (stacked) {
if (presentedSheets.contains(fragmentTag)) return
presentedSheets.add(fragmentTag)
Expand All @@ -222,20 +229,58 @@ open class AppFittedSheet(context: Context) : ViewGroup(context), LifecycleEvent

override fun addView(child: View, index: Int) {
UiThreadUtil.assertOnUiThread()
if (useInlinePresentation && index > 0) {
inlineOverlayView = child
inlinePresenter.setOverlayView(child)
return
}
if (!useInlinePresentation && index > 0) {
dialogOverlayView = child
sheet?.setOverlayView(child)
return
}
mHostView.addView(child, index)
}

override fun getChildCount(): Int = mHostView.childCount
override fun getChildCount(): Int =
mHostView.childCount +
(if (inlineOverlayView != null) 1 else 0) +
(if (dialogOverlayView != null) 1 else 0)

override fun getChildAt(index: Int): View? = mHostView.getChildAt(index)
override fun getChildAt(index: Int): View? {
if (index < mHostView.childCount) return mHostView.getChildAt(index)
val overlayIndex = index - mHostView.childCount
if (inlineOverlayView != null && overlayIndex == 0) return inlineOverlayView
return dialogOverlayView
}

override fun removeView(child: View) {
UiThreadUtil.assertOnUiThread()
if (child == inlineOverlayView) {
inlineOverlayView = null
inlinePresenter.setOverlayView(null)
return
}
if (child == dialogOverlayView) {
dialogOverlayView = null
sheet?.setOverlayView(null)
return
}
dismiss()
}

override fun removeViewAt(index: Int) {
UiThreadUtil.assertOnUiThread()
if (useInlinePresentation && index >= mHostView.childCount && inlineOverlayView != null) {
inlineOverlayView = null
inlinePresenter.setOverlayView(null)
return
}
if (!useInlinePresentation && index >= mHostView.childCount && dialogOverlayView != null) {
dialogOverlayView = null
sheet?.setOverlayView(null)
return
}
dismiss()
}

Expand Down
17 changes: 9 additions & 8 deletions android/src/main/java/com/sheet2/BaseRNView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,7 @@ open class BaseRNView(context: Context?) : ReactViewGroup(context), RootView {

override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
if (!inlineMode) {
eventDispatcher?.let { eventDispatcher ->
jSTouchDispatcher.handleTouchEvent(event, eventDispatcher, reactContext)
jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, true)
}
dispatchTouchEventToJs(event, isCapture = true)
}
return super.onInterceptTouchEvent(event)
}
Expand All @@ -90,10 +87,7 @@ open class BaseRNView(context: Context?) : ReactViewGroup(context), RootView {
// touch events or eat the event; let normal target finding run.
return super.onTouchEvent(event)
}
eventDispatcher?.let { eventDispatcher ->
jSTouchDispatcher.handleTouchEvent(event, eventDispatcher, reactContext)
jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, false)
}
dispatchTouchEventToJs(event, isCapture = false)
super.onTouchEvent(event)
// In case when there is no children interested in handling touch event, we return true from
// the root view in order to receive subsequent events related to that gesture
Expand Down Expand Up @@ -124,4 +118,11 @@ open class BaseRNView(context: Context?) : ReactViewGroup(context), RootView {
// No-op - override in order to still receive events to onInterceptTouchEvent
// even when some other view disallow that
}

private fun dispatchTouchEventToJs(event: MotionEvent, isCapture: Boolean) {
eventDispatcher?.let { eventDispatcher ->
jSTouchDispatcher.handleTouchEvent(event, eventDispatcher, reactContext)
jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, isCapture)
}
}
}
11 changes: 10 additions & 1 deletion android/src/main/java/com/sheet2/DialogRootViewGroup.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import kotlin.math.min

class DialogRootViewGroup(context: Context) : BaseRNView(context) {
private var reactView: View? = null
var onSheetLayoutChanged: (() -> Unit)? = null

var sheetMaxHeightSize = Float.MAX_VALUE
var sheetMaxWidthSize = Float.MAX_VALUE
Expand Down Expand Up @@ -56,6 +57,10 @@ class DialogRootViewGroup(context: Context) : BaseRNView(context) {
}
}

private fun notifySheetLayoutChanged() {
post { onSheetLayoutChanged?.invoke() }
}

fun setVirtualHeight(h: Float) {
if (reactView == null) return
this.sheetMaxHeightSize = h
Expand All @@ -68,6 +73,7 @@ class DialogRootViewGroup(context: Context) : BaseRNView(context) {
translationX = ((metrics.displayMetrics.widthPixels - newWidth) / 2).toFloat()
layoutParams?.width = newWidth
layout()
notifySheetLayoutChanged()
}

fun updateMaxWidth(value: Float) {
Expand All @@ -76,6 +82,7 @@ class DialogRootViewGroup(context: Context) : BaseRNView(context) {
translationX = ((metrics.displayMetrics.widthPixels - newWidth) / 2).toFloat()
layoutParams?.width = newWidth
layout()
notifySheetLayoutChanged()
}

override fun addView(child: View, index: Int, params: LayoutParams) {
Expand All @@ -96,7 +103,9 @@ class DialogRootViewGroup(context: Context) : BaseRNView(context) {
super.removeViewAt(index)
}

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
notifySheetLayoutChanged()
}

private fun releaseReactView() {
sheetMaxHeightSize = Float.MAX_VALUE
Expand Down
59 changes: 59 additions & 0 deletions android/src/main/java/com/sheet2/FragmentModalBottomSheet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@ import android.content.DialogInterface
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.FrameLayout
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import java.lang.ref.WeakReference

class FragmentModalBottomSheet() : BottomSheetDialogFragment() {

private var modalView: ViewGroup? = null
private var overlayHost: ViewGroup? = null
private var overlayView: View? = null
private var dismissable: Boolean = true
private var isSystemUILight: Boolean = false
private var onDismiss: ((dismissAll: Boolean) -> Unit)? = null
Expand Down Expand Up @@ -64,6 +68,53 @@ class FragmentModalBottomSheet() : BottomSheetDialogFragment() {
return dialog
}

override fun onStart() {
super.onStart()
attachOverlayView()
}

fun setOverlayView(view: View?) {
if (overlayView == view) return
detachOverlayView()
overlayView = view
attachOverlayView()
}

private fun attachOverlayView() {
val view = overlayView ?: return
val decorView = dialog?.window?.decorView as? ViewGroup ?: return
detachOverlayHost()
(view.parent as? ViewGroup)?.removeView(view)

val host = DialogPassThroughFrameLayout(decorView.context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
isClickable = false
isFocusable = false
}

view.layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
host.addView(view)
decorView.addView(host)
host.bringToFront()
overlayHost = host
}

private fun detachOverlayHost() {
(overlayHost?.parent as? ViewGroup)?.removeView(overlayHost)
overlayHost = null
}

private fun detachOverlayView() {
detachOverlayHost()
(overlayView?.parent as? ViewGroup)?.removeView(overlayView)
}

fun setNewNestedScrollView(view: View) {
(dialog as CustomBottomSheetDialog).setNewNestedScrollView(view)
}
Expand All @@ -78,8 +129,16 @@ class FragmentModalBottomSheet() : BottomSheetDialogFragment() {

override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
detachOverlayView()
overlayView = null
presentedWindow?.clear()
presentedWindow = null
onDismiss?.invoke(dismissAll)
}
}

private class DialogPassThroughFrameLayout(context: android.content.Context) : FrameLayout(context) {
override fun dispatchTouchEvent(ev: MotionEvent): Boolean = false
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean = false
override fun onTouchEvent(event: MotionEvent): Boolean = false
}
Loading
Loading