Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Android): separate transitions of sheet and dimming view #2542

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft
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
83 changes: 80 additions & 3 deletions android/src/main/java/com/swmansion/rnscreens/Screen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import android.annotation.SuppressLint
import android.content.pm.ActivityInfo
import android.graphics.Paint
import android.os.Parcelable
import android.util.Log
import android.util.SparseArray
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
Expand All @@ -18,6 +20,7 @@ import com.facebook.react.bridge.GuardedRunnable
import com.facebook.react.bridge.ReactContext
import com.facebook.react.uimanager.PixelUtil
import com.facebook.react.uimanager.ReactClippingViewGroup
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.uimanager.UIManagerModule
import com.facebook.react.uimanager.events.EventDispatcher
Expand All @@ -29,11 +32,12 @@ import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel
import com.swmansion.rnscreens.events.HeaderHeightChangeEvent
import com.swmansion.rnscreens.events.SheetDetentChangedEvent
import com.swmansion.rnscreens.ext.parentAsViewGroup
import java.lang.ref.WeakReference

@SuppressLint("ViewConstructor") // Only we construct this view, it is never inflated.
class Screen(
val reactContext: ReactContext,
val reactContext: ThemedReactContext,
) : FabricEnabledViewGroup(reactContext),
ScreenContentWrapper.OnLayoutCallback {
val fragment: Fragment?
Expand Down Expand Up @@ -113,7 +117,7 @@ class Screen(
* `fitToContents` for formSheets, as this is first entry point where we can acquire
* height of our content.
*/
override fun onLayoutCallback(
override fun onContentWrapperLayout(
changed: Boolean,
left: Int,
top: Int,
Expand All @@ -125,6 +129,7 @@ class Screen(
if (sheetDetents.count() == 1 && sheetDetents.first() == SHEET_FIT_TO_CONTENTS) {
sheetBehavior?.let {
if (it.maxHeight != height) {
Log.i(TAG, "[Screen] Received maxHeight from content wrapper: $height")
it.maxHeight = height
}
}
Expand All @@ -146,6 +151,16 @@ class Screen(
// ignore restoring instance state too as we are not saving anything anyways.
}

override fun onMeasure(
widthMeasureSpec: Int,
heightMeasureSpec: Int,
) {
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = MeasureSpec.getSize(heightMeasureSpec)
Log.i(TAG, "[Screen] Measured with $width $height")
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}

override fun onLayout(
changed: Boolean,
l: Int,
Expand Down Expand Up @@ -376,10 +391,56 @@ class Screen(
fun startRemovalTransition() {
if (!isBeingRemoved) {
isBeingRemoved = true

val coordinatorLayout = this.parentAsViewGroup()!!
val containerView = coordinatorLayout.parentAsViewGroup()!!
assert(containerView == container)

containerView.startViewTransition(coordinatorLayout)

// Following call seems to be optional, because no one tries to detach these:
coordinatorLayout.children.forEach {
coordinatorLayout.startViewTransition(it)
}

startTransitionRecursive(this)
}
}

fun endRemovalTransition() {
if (!isBeingRemoved) {
return
}

isBeingRemoved = false

val coordinatorLayout = this.parentAsViewGroup()!!
assert(coordinatorLayout is CoordinatorLayout)
//
val containerView = coordinatorLayout.parentAsViewGroup()!!
// assert(containerView is ScreenStack)
// assert(containerView == container || container == null)

// TransitionManager.controlDelayedTransition()
containerView.endViewTransition(coordinatorLayout)
coordinatorLayout.children.forEach { coordinatorLayout.endViewTransition(it) }
endTransitionRecursive(this)
}

private fun endTransitionRecursive(parent: ViewGroup) {
parent.children.forEach { childView ->
parent.endViewTransition(childView)

if (childView is ScreenStackHeaderConfig) {
endTransitionRecursive(childView.toolbar)
}

if (childView is ViewGroup) {
endTransitionRecursive(childView)
}
}
}

private fun startTransitionRecursive(parent: ViewGroup?) {
parent?.let {
for (i in 0 until it.childCount) {
Expand Down Expand Up @@ -421,7 +482,7 @@ class Screen(
// Is this ugly? Very. Do we have better option before changes land in core?
// I'm not aware of any.
try {
for (j in 0 until child.childCount) {
repeat(child.childCount) {
child.addView(View(context))
}
} catch (_: Exception) {
Expand All @@ -433,6 +494,22 @@ class Screen(
}
}

override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
Log.i(TAG, "[Screen] onInterceptTouchEvent")
return super.onInterceptTouchEvent(ev)
}

override fun onTouchEvent(event: MotionEvent?): Boolean {
Log.i(TAG, "[Screen] onTouchEvent")
// If we're a form sheet we want to consume the gestures to prevent
// DimmingView's callback from triggering when clicking on the sheet itself.
return if (stackPresentation === StackPresentation.FORM_SHEET) {
true
} else {
super.onTouchEvent(event)
}
}

private fun notifyHeaderHeightChange(headerHeight: Int) {
val screenContext = context as ReactContext
val surfaceId = UIManagerHelper.getSurfaceId(screenContext)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.swmansion.rnscreens

import android.annotation.SuppressLint
import android.icu.util.Measure
import android.util.Log
import com.facebook.react.bridge.ReactContext
import com.facebook.react.views.view.ReactViewGroup

Expand All @@ -17,7 +19,7 @@ class ScreenContentWrapper(
internal var delegate: OnLayoutCallback? = null

interface OnLayoutCallback {
fun onLayoutCallback(
fun onContentWrapperLayout(
changed: Boolean,
left: Int,
top: Int,
Expand All @@ -26,13 +28,21 @@ class ScreenContentWrapper(
)
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = MeasureSpec.getSize(heightMeasureSpec)
Log.i("ScreenContentWrapper", "[ContentWrapper] measured $width $height")
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}

override fun onLayout(
changed: Boolean,
left: Int,
top: Int,
right: Int,
bottom: Int,
) {
delegate?.onLayoutCallback(changed, left, top, right, bottom)
Log.i("ScreenContentWrapper", "[ContentWrapper] received layout: ${right - left}, ${bottom - top}")
delegate?.onContentWrapperLayout(changed, left, top, right, bottom)
}
}
15 changes: 12 additions & 3 deletions android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package com.swmansion.rnscreens
import android.content.Context
import android.graphics.Canvas
import android.os.Build
import android.util.Log
import android.view.View
import com.facebook.react.bridge.ReactContext
import com.facebook.react.uimanager.UIManagerHelper
import com.swmansion.rnscreens.Screen.StackAnimation
import com.swmansion.rnscreens.bottomsheet.DimmingFragment
import com.swmansion.rnscreens.events.StackFinishTransitioningEvent
import java.util.Collections
import kotlin.collections.ArrayList
Expand Down Expand Up @@ -50,7 +50,7 @@ class ScreenStack(

override fun adapt(screen: Screen): ScreenStackFragmentWrapper =
when (screen.stackPresentation) {
Screen.StackPresentation.FORM_SHEET -> DimmingFragment(ScreenStackFragment(screen))
Screen.StackPresentation.FORM_SHEET -> ScreenStackFragment(screen)
else -> ScreenStackFragment(screen)
}

Expand All @@ -67,6 +67,16 @@ class ScreenStack(
}
}

override fun onViewRemoved(child: View?) {
Log.i(TAG, "[Stack] onViewRemoved: $child")
super.onViewRemoved(child)
}

override fun onViewAdded(child: View?) {
Log.i(TAG, "[Stack] onViewAdded: $child")
super.onViewAdded(child)
}

fun onViewAppearTransitionEnd() {
if (!removalTransitionStarted) {
dispatchOnFinishTransitioning()
Expand Down Expand Up @@ -242,7 +252,6 @@ class ScreenStack(
}
}
}

// animation logic end
goingForward = shouldUseOpenAnimation

Expand Down
Loading
Loading