Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,12 @@ internal constructor(
// View in the future.
if (currParentView is ViewGroup) {
currParentView.removeView(view)
// If the view is being animated out of its previous parent (e.g. by a LayoutTransition),
// ViewGroup has already dropped it from its children but keeps its parent pointer until
// the transition ends, so removeView above is a no-op. End the transition to detach it.
if (view.parent === currParentView) {
currParentView.endViewTransition(view)
}
}
erroneouslyReaddedReactTags.add(tag)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

package com.facebook.react.fabric

import android.view.ViewGroup
import com.facebook.react.ReactRootView
import com.facebook.react.bridge.JavaOnlyMap
import com.facebook.react.bridge.ReactTestHelper
Expand Down Expand Up @@ -192,4 +193,32 @@ class SurfaceMountingManagerTest {
smm.preallocateView("RCTView", 42, JavaOnlyMap.of(), null, true)
assertThat(smm.getViewExists(42)).isTrue()
}

/**
* When a child is moved between parents (e.g. because an intermediate view is flattened or
* unflattened) while it is still being animated out of its previous parent, [ViewGroup] removes
* it from its children but keeps its parent pointer until the transition ends. addViewAt must
* still be able to insert it into the new parent.
*/
@Test
fun addViewAt_reparentsViewThatIsTransitioningOutOfPreviousParent() {
val smm = startSurface()
smm.createView("RCTView", 10, JavaOnlyMap.of(), null, null, true)
smm.createView("RCTView", 12, JavaOnlyMap.of(), null, null, true)
smm.createView("RCTView", 42, JavaOnlyMap.of(), null, null, true)
smm.addViewAt(surfaceId, 10, 0)
smm.addViewAt(surfaceId, 12, 1)
smm.addViewAt(10, 42, 0)

val previousParent = smm.getView(10) as ViewGroup
val view = smm.getView(42)
previousParent.startViewTransition(view)
smm.removeViewAt(42, 10, 0)
assertThat(previousParent.indexOfChild(view)).isEqualTo(-1)
assertThat(view.parent).isSameAs(previousParent)

smm.addViewAt(12, 42, 0)

assertThat(view.parent).isSameAs(smm.getView(12))
}
}
Loading