The Modifier allows us to customize the appearance of the composable. Using it, you can:
- Change a Composable’s appearance, size, offset, padding or margin
- Add interactions, like making an element clickable, scrollable, draggable, or zoomable
- Change its scale, position in screen while its layout somewhere different entirely, or shape that changes its touch area.
Based on which order you place these modifiers your Composable's visual and behavioral structure is shaped.
Most of the modifiers are applied from from top to bottom or left to right. One exception is Modifier.pointerInput() it gets applied from right to left or bottom to top by default pass.
Modifier.padding()
Modifier.padding()
in Jetpack Compose acts as padding or margin depending on order.
Modifier.padding(10.dp).size(200.dp)
adds space before setting size you have a Composable with 200.dp size
Modifier.size(200.dp).padding(10.dp)
adds padding which you have 180.dp width and height after setting 10.dp padding on each side.
Box(
Modifier
.border(2.dp, Color.Green)
.padding(10.dp)
.border(2.dp, Color.Red)
.size(200.dp)
)
Box(
Modifier
.border(2.dp, Color.Cyan)
.size(200.dp)
.padding(10.dp)
.border(2.dp, Color.Magenta)
)
And padding modifiers are cumulative. Modifier.padding(20.dp).padding(20.dp)
is summed as 40.dp.
Box(
Modifier
.border(2.dp, Color.Green)
.padding(20.dp)
.border(2.dp, Color.Red)
.size(200.dp)
)
Box(
Modifier
.border(2.dp, Color.Green)
.padding(20.dp)
.padding(20.dp)
.border(2.dp, Color.Red)
.size(200.dp)
)
Modifier.shadow()
Another modifier that changes appearance of Composable based on which order it's applied. For shadow to be applied as outside of Composable it should be applied before background or other modifiers. If you apply it after Modifier.background
you can have outer shadow.
Box(
Modifier
.shadow(5.dp, RoundedCornerShape(8.dp))
.background(Color.White)
.size(100.dp)
)
Box(
Modifier
.background(Color.White)
.size(100.dp)
.shadow(5.dp, RoundedCornerShape(8.dp))
)
Modifier.clip()
This Modifier also clips the Modifiers depending on order it's placed. Good thing with this modifier if you place it before Modifier.clickable{}
you can change or clip clickable area of a Composable. Having a circle, triangle or diamond circle area or creating before/after layout is possible using this modifier and Shape
s.
It's Modifier.graphicsLayer{}
under the hood, you can check out my detailed answer about it here, here and here. It helps you create complex layouts using scale, shape, clip, translate, and other cool properties.
Modifier.offset()
This Modifier is useful for changing position of a Composable after it's laid out unlike Modifier.padding changing value of this Modifier does not change position of a Composable relative to its sibling Composable. However depending on where you set Modifier.offset you can change touch area of a Composable and it has two variants. One that takes lambda defers state read which is advised by google over the one that takes value.
I used one with value for demonstration. You can see if offset is applied first ever modifier that follow offset is moved as Slider changes values. In second example touch area of Composable is not changed because Modifier.clickable{}
is applied before Modifier.offset{}
var offset by remember {
mutableStateOf(0f)
}
Box(
Modifier
.offset(x = offset.dp)
.clickable {}
.background(Color.Red)
.size(100.dp)
)
Box(
Modifier
.clickable {}
.offset(x = offset.dp)
.background(Color.Red)
.size(100.dp)
)
Slider(value = offset, onValueChange = { offset = it }, valueRange = 0f..200f)
Modifier.pointerInput(keys)
This modifier is basis of gesture and touch events. Using it drag, tap, press, double tap, zoom, rotation and many gesturer can be invoked. In this answer how it's used is explained to build onTouchEvent counterpart of View system.
Unlike Modifiers above it propagates by default from bottom to top unless you consume PointerInputChange. In Compose gesture system consuming continuous events cancel next one in line to receive it. So you can prevent gestures like scroll not happening when you zoom an image for instance.
Modifier
.pointerInput() // Second one that is invoked
.pointerInput() // First one that is invoked