Jetpack Compose provides modifiers
to change the look and feel of the Composable. But the order in which modifiers
are provided affects the outcome of the Composable.
In XML based approach these values were provided via properties in XML and it didn’t matter in which order you provide But in Compose it does matter.
In order to understand this Let’s take an example.
In the example below we are showing a Box
with chain of modifiers
as mentioned below.
Box( | |
Modifier | |
.border(1.dp, Color.Red) | |
.padding(10.dp) | |
.size(40.dp) | |
.background(Color.Green) | |
) |
The Output of the above code via Composable Preview window
Now Let’s take the same example code and just change the order of the modifiers
by swapping border
modifier with padding
modifier, as shown below.
Box( | |
Modifier | |
.padding(10.dp) | |
.border(1.dp, Color.Red) | |
.size(40.dp) | |
.background(Color.Green) | |
) |
The output of above code will be different as shown below i.e the red bordered Square is now around the green box
We just saw changing the chain of modifiers
to rearrange the same modifiers in different order impacts the output of the composable.
How does the order of modifiers affect the outcome?
To understand, we need to see Under The Hood how Compose UI is drawn from Composable functions.
Compose transform Data into UI via three phases as shown below
Composition
—What to show?: Compose Runtime goes through Composable functions, sees what has to be shown and builds a tree structure that represents UI. Each node in that structure is aLayout Node
which contains information for the next phase in the process.Layout
— Where to show?: This phase takes tree structure as input , traverses it, going through each node and its children measuring thewidth
,height
andx
/y
coordinates of its children and eventually of its own node in a 2D Space.Drawing
— How to render?: This traverses the tree structure node by node and draws each node on 2D screen pixel by pixel.
Layout and Drawing Phases
Layout phase determines the placement x
&y
and size width
& height
of each layout and its children using modifiers
and constraints
.
Drawing Phase draws the layout and applies modifiers
that need to apply in the Drawing phase.
Some of the modifiers
have an impact in Drawing
phase such as border
, clip
modifiers
are related to drawing and they get applied only in Drawing
phase of the Composition. These modifiers are applied in the chain of modifiers
from Right
to Left
.
Similarly some modifiers
have an impact in Layout
phase. In general all of those modifiers
which can impact the size and the placement of UI elements are applied in Layout
phase such as size
, padding
, fillMaxSize
, sizeIn
, wrapContentSize
, requiredSize
etc. These modifiers are applied in the chain of modifiers
from Left
to Right
.
So to understand the full picture how modifiers
are applied together we will look at these two phases together.
Before moving forward one more point to keep in mind that in Layout
phase constraints
and modifiers
are applied together to decide the final size
and placement
of each UI element.
Such as in Layout
phase each node passes its constraints
to its children nodes restricting them to not exceed the boundaries out of those constraints
then children nodes decide its size within those constraints
and pass on updated constraints to their children further so on and at the end parent node
decides its size and placement once all of its children are decided.
Let’s see now how modifiers
are applied via a diagram, We will take the code example as shown above in the first example.
Box( | |
Modifier | |
.border(1.dp, Color.Red) | |
.padding(10.dp) | |
.size(40.dp) | |
.background(Color.Green) | |
) |
Below diagram shows how modifiers
get applied.
In the diagram each arrow is labeled with number 1, 2,3 etc showing the order of modifiers
applied.
Layout Phase:
Represented with top arrows going from Left
to Right
Drawing Phase:
Represented with bottom arrows going from Right
to Left
As mentioned before the modifiers
which impact the size and placement of the UI element are applied from Left
to Right
which are mentioned in the diagram with the top arrows going from Left
to Right
numbered 1, 2 and 3 as these modifiers
impact the size and placement.
The bottom arrows 4 and 6 show modifiers
which are applied during the Drawing
phase so they are applied from Right
to Left
which are mentioned with the bottom arrows going from Right
to Left
.
Each top arrow in Layout
phase which are labeled 1, 2 and 3 have constraints
which are passed from Left
to Right
keeping the next modifier
not to exceed the provided constraints
coming from the previous modifier
. On every step the constraints
get updated due to modifiers
and updated constraints
are then passed to the next modifiers
and so on.
Let’s see the diagram for the 2nd code example.
Box( | |
Modifier | |
.padding(10.dp) | |
.border(1.dp, Color.Red) | |
.size(40.dp) | |
.background(Color.Green) | |
) |
Let’s see how UI is drawn.
We can see the final size of the Box
is finalised to 40dp
and inner green box size is now reduced to 20dp
due to 10dp
padding
applied on both sides after size
modifier
.
Let’s see further some other modifiers how they impact.
E.g let’s add clickable
modifier in the start and end of the chain of modifiers
around a Box.
Adding clickable
at the start of the chain of modifiers
.
Box( | |
Modifier | |
.clickable { } | |
.border(1.dp, Color.Red) | |
.size(40.dp) | |
.padding(10.dp) | |
.background(Color.Green) | |
) |
Let’s see the tap
effect.
We can see that it makes the whole area as tappable as we wanted.
But let’s now move the clickable
modifier to the end of the same chain of modifiers
as below.
Box( | |
Modifier | |
.border(1.dp, Color.Red) | |
.size(40.dp) | |
.padding(10.dp) | |
.background(Color.Green) | |
.clickable { } | |
) |
And the tap
effect looks like this below.
Now only the inner green box is tappable rather than the whole Box
.
Summary
- Compose requires a shift in mental model in building look and feel from previous XML based approach to new Compose based UI.
- Composition is split into three phases
Compose
,Layout
andDrawing
- The order of
modifiers
matters it impacts the outcome of the UI look and feel. - Modifiers which affect the
size
andplacement
of the UI element are applied first and fromLeft
toRight
suchmodifiers
are likesize
,padding
,requiredSize
and so on. These modifiers are applied duringLayout
phase of composition. - Modifiers which do not affect the
size
andplacement
are applied fromRight
toLeft
such modifiers are likeclip
,border
,clickable
etc These Modifiers are applied during theDrawing
phase of Composition.