Introduce support for rendering across subcompositions.#104
Merged
zach-klippenstein merged 2 commits intomainfrom Oct 14, 2020
Merged
Introduce support for rendering across subcompositions.#104zach-klippenstein merged 2 commits intomainfrom
zach-klippenstein merged 2 commits intomainfrom
Conversation
443f61e to
d9180b2
Compare
compose-tests/src/androidTest/java/radiography/test/compose/ComposeUiTest.kt
Outdated
Show resolved
Hide resolved
d9180b2 to
708687f
Compare
pyricau
reviewed
Oct 14, 2020
radiography/src/main/java/radiography/internal/CompositionReferences.kt
Outdated
Show resolved
Hide resolved
pyricau
approved these changes
Oct 14, 2020
Fixes #93. Subcomposition is where a reference is created to a particular position in a parent composition, and then that reference is used as the parent of a separate composition. The subcomposition inherits ambients and recompose scopes from the parent, but can be created at any point in the lifetime of the parent, and disposed before the parent composition is disposed. From the kdoc: ``` A [CompositionReference] is an opaque type that is used to logically "link" two compositions together. The [CompositionReference] instance represents a reference to the "parent" composition in a specific position of that composition's tree, and the instance can then be given to a new "child" composition. This reference ensures that invalidations and ambients flow logically through the two compositions as if they were not separate. ``` Subcomposition is used for a number of things: 1. Compose children which have a data dependency on a property of the parent composition that is only available after the composition pass, e.g. `WithConstraints` (which can only compose its children during layout). 2. Lazy composition, where the "current" actual children of a composable depend on some runtime state, and old/uncreated children should be not be composed when not needed, to save resources. `LazyColumn` does this. 3. Linking compositions that need to be hosted in entirely separate windows together. `Dialog` uses this to make the dialog children act as children of the composable that invokes them, even though they're hosted in a separate window, with a Android view host. Rendering subcomposition is tricky, because there's no explicit reference from the parent `CompositionReference` to where the subcompositions' composables actually appear. Fortunately, `SubcomposeLayout` is a helper composable which provides a convenient wrapper around subcomposition for common use cases such as 1 and 2 above – basically any time the subcomposition is actually a visual child of the parent composable, but can only be created during the layout pass. `SubcomposeLayout` shows up as a pattern in the slot tables' groups which Radiography detects and renders in a way that makes the subcomposition look like regular children of the parent composable. Non-`SubcomposeLayout` subcompositions, like the one from `Dialog`, are rendered slightly more awkwardly. The subcomposition is shown as a child of the parent layout node. In the case of `Dialog`, this is fine, since there's no actual layout node in the parent composition which acts as a parent for the subcomposition. More complex use cases may be rendered differently, e.g. if there's a layout node which "hosts" the subcomposition, it will appear after the actual `CompositionReference` in the slot table, and thus the subcomposition and its subtree will appear before the layout node in the rendering. Subcompositions are detected by looking for instances of `CompositionReference` in the slot table. `CompositionReference` is an abstract class, but the only concrete implementation currently in Compose contains references to all actual compositions that use it as a parent. Reflection is used to pull the actual subcompositions out of the parent reference, and then those compositions' slot tables are analyzed in turn.
708687f to
c9d3758
Compare
Collaborator
Author
|
Tweaked the rendering a bit, so the children of each subcomposition is grouped under that particular subcomposition. For stuff like |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
tl;dr: The first commit in this PR adds tests for the current (lack of) subcomposition support. See the test changes in the second commit to see the changes in renderings.
Fixes #93.
Subcomposition is where a reference is created to a particular position in a
parent composition, and then that reference is used as the parent of a separate
composition. The subcomposition inherits ambients and recompose scopes from the
parent, but can be created at any point in the lifetime of the parent, and
disposed before the parent composition is disposed. From the kdoc:
Subcomposition is used for a number of things:
composition that is only available after the composition pass, e.g.
WithConstraints(which can only compose its children during layout).on some runtime state, and old/uncreated children should be not be composed
when not needed, to save resources.
LazyColumndoes this.Dialoguses this to make the dialog children act as children of the composablethat invokes them, even though they're hosted in a separate window, with a
Android view host.
Rendering subcomposition is tricky, because there's no explicit reference from the
parent
CompositionReferenceto where the subcompositions' composables actually appear.Fortunately,
SubcomposeLayoutis a helper composable which provides a convenientwrapper around subcomposition for common use cases such as 1 and 2 above – basically
any time the subcomposition is actually a visual child of the parent composable, but
can only be created during the layout pass.
SubcomposeLayoutshows up as a patternin the slot tables' groups which Radiography detects and renders in a way that makes
the subcomposition look like regular children of the parent composable.
Non-
SubcomposeLayoutsubcompositions, like the one fromDialog, are renderedslightly more awkwardly. The subcomposition is shown as a child of the parent
layout node. In the case of
Dialog, this is fine, since there's no actual layoutnode in the parent composition which acts as a parent for the subcomposition. More
complex use cases may be rendered differently, e.g. if there's a layout node which
"hosts" the subcomposition, it will appear after the actual
CompositionReferencein the slot table, and thus the subcomposition and its subtree will appear before
the layout node in the rendering.
Subcompositions are detected by looking for instances of
CompositionReferenceinthe slot table.
CompositionReferenceis an abstract class, but the only concreteimplementation currently in Compose contains references to all actual compositions
that use it as a parent. Reflection is used to pull the actual subcompositions out
of the parent reference, and then those compositions' slot tables are analyzed in
turn.
As an example, the nested composables used to render the Radiography logo in the compose sample app are now rendered correctly:
