<@U0KMMQA20> one of the trickiest things I have ex...
# squarelibraries
b
@Zach Klippenstein (he/him) [MOD] one of the trickiest things I have experienced while building features with Scoop (Lyft) framework was transition animations between two views/plugins (with a potential shared element). It also seems like it is not trivial in Ribs (Uber's) either. How would you envisage this being achieved easily in (Android) worklow where the animations is shared between two workflows? I imagine the transitions could be done by passing in a prop into the secondary workflow; the result of the first workflow would be the input prop of the secondary one?
z
Workflows themselves aren’t concerned with view stuff like transition animations, so it’s really up to you.
The Android View integration we ship is also pretty unopinionated – I don’t think we have a sample, but @Ray Ryan has said it should be flexible enough to work with Android’s standard shared element transition support I believe.
r
We solved it by not trying to solve it, trying not to get in the way of plain old view code running plain old Android animations.
e.g. our
BackStackContainer
has push and pop animations built in, and decides which one to run based on the difference based on the last stack the workflow wanted displayed, and the next one.
The method that runs the animation is open: customize by subclassing.
Or customize by forking, all the tricky bits are in a public helper class.
wrt communication between two screens, they don’t normally know about each other.
or that they’re in a backstack or whatever
ScreenA runs, emits an output of some kind
A parent workflow, aware of backstack navigation, decides to move to ScreenB based on that output, as well as what props to provide ScreenB
And if a backstack display is what it wants, the rendering it returns from
render()
is something like
BackStackScreen(renderingOfScreenA, renderingOfScreenB)
A pop operation is basically, ScreenBWorkflow emits an output that means “hey, they pressed the back button, isn’t that interesting”
And the parent workflow knows that means that it’s time to run ScreenA workflow again, and emit
BackStackScreen(renderingOfScreenA)
So…is that what you were asking?
b
Yeah, I saw the code sample for the
BackStackScreen
. Extracting view code (from the workflow) makes sense. And yeah, that's more or less what I was asking. I have been playing around with a playground project, where I have a parent workflow which would be aware of the navigation between its children, but additionally, I want the emissions/result of one (this could be data related to an element item in a recyclerview for example) to be used as a basis to create a transition animation to the new rendering (
B
). Much like what you see below. Of course, this could all be one rendering (but I'd rather separate them). I wanted an opinion (if any at all) on this approach, or whether Square's Android team approaches this in the same manner. Thanks again.
r
Neat. Thinking.
In the beginning, is the idea that each tile is the rendering of a different workflow, and then you transition to showing only sneakers workflow?
b
No, the first rendering ideally would be one workflow whose rendering contains a grid or recyclerview, displaying the images. When the user clicks one of the images, it transition into the secondary (detail) workflow; much like when you move from one fragment to another. In the sample code, this would be similar to the poem app, where clicking one transition to a fuller rendering (workflow).
r
Regardless of how you shape the workflows, I’d start by thinking in terms of renderings. You’ve got a custom container, maybe a subclass of BackStackContainer, that is aware of a couple of special wrapper rendering types. Say, BrunoGrid and BrunoFrame.
Copy code
class BrunoGrid(
  val cells: List<BrunoGridCell>
)

class BrunoGridCell(
  val id: String,
  val photoUrl: String
 // etc.
)
Copy code
class BrunoFrame(
  val id: String
  val wrapped: Any
)
When a BrunoGrid renders, it includes the cell id in a view tag or something.
When your container updates, if it sees that it’s moving from a grid to a frame, it uses the id of the frame to find the grid view with the matching tag.
Use a WorkflowViewStub to render BrunoFrame.wrapped, and set up transition animation from the old view with that tag to the full frame new view.
I’d hope that TransitionManager could make that as simple as it sounds, but I haven’t used it in anger much. But even the custom animation doesn’t sound too bad to me.
b
Thanks Ray. Will try out your idea. 👍 👏
r
To keep the container from having to know too much about all the details of the grid and the cells, you could have ViewFactories registered for both types, that do the work of putting the tags in place.
Then the container could just look for matching tags of that name on outgoing and incoming views.
We haven’t put in generalized support yet, but there are examples of “aliasing” view factories, that don’t actually create views themselves, but instead delegate to the wrapped rendering and play games with the meta data. I’m thinking you could have register a BrunoFrame ViewFactory does the bit about inflating the wrapped field and setting a tag.
So really, you could use that on the cells in the grid. And then a BrunoGrid rendering that does the recyclerview or whatever. I’m going into the weeds, but the point buried in here is that ViewRegistry entries and workflows needn’t be 1:1
ViewRegistry and its factories are like poor man’s Compose. And Workflows can rendering assemblages of renderings as useful.
That was a fun question, thanks. So much better than working.
😂 1
b
Thanks again Ray. Plenty to play around with now.