How to add Margin in Jetpack Compose?

27,431

Solution 1

You can consider padding and margin as the same thing (imagine it as "spacing"). A padding can be applied twice (or more) in the same composable and achieve the similar behavior you would get with margin+padding. For example:

val shape = CircleShape
Text(
    text = "Text 1",
    style = TextStyle(
        color = Color.White,
        fontWeight = FontWeight.Bold,
        textAlign = TextAlign.Center),
    modifier = Modifier.fillMaxWidth()
        .padding(16.dp)
        .border(2.dp, MaterialTheme.colors.secondary, shape)
        .background(MaterialTheme.colors.primary, shape)
        .padding(16.dp)
)

Will result on this:

enter image description here

As you can see, the first padding is adding a space between the component and its border. Then the background and border are defined. Finally, a new padding is set to add space between the border and the text.

Solution 2

Thinking in terms of padding and margin you refer to the so-called box model that we are used to. There's no a box model in Compose but a sequence of modifiers which is applied to a given composable. The trick is that you can apply the same modifier like padding or border multiple times and the order of these matters, for example:

@Composable
fun PaddingExample() {
    Text(
        text = "Hello World!",
        color = Color.White,
        modifier = Modifier
            .padding(8.dp) // margin
            .border(2.dp, Color.White) // outer border
            .padding(8.dp) // space between the borders
            .border(2.dp, Color.Green) // inner border
            .padding(8.dp) // padding
    )
}

As the result you'll get this composable:

enter image description here

This design is well explained in the Modifiers documentation:

Note: The explicit order helps you to reason about how different modifiers will interact. Compare this to the view-based system where you had to learn the box model, that margins applied "outside" the element but padding "inside" it, and a background element would be sized accordingly. The modifier design makes this kind of behavior explicit and predictable, and gives you more control to achieve the exact behavior you want.

Solution 3

You can achieve the same effect as margin with putting your content, that has padding, inside a different composable like Box and make outer composable clickable. With this approach, inner padded areas will be included in clickable content.

Solution 4

I was also looking for something which should give me a direct option to set margin on a View like TextView. But unfortunately we don't have margin support in Jetpack compose. But the good news is we can still achieve it by using layout container like Box, which allows us to add views like TextView, ImageView etc. So you can add margin to any of the child(TextView) by using padding modifier to the parent(Box). Here is the code:

Box(Modifier.padding(10.dp)) {
    Surface(color = Color.LightGray) {
        Text(text = "Hello $text!", color = Color.Blue,
            modifier = Modifier.padding(16.dp))
    }
}

And the result is:

enter image description here

Here I have given 10.dp padding to the box. Hope it is useful.

Share:
27,431
Archie G. Quiñones
Author by

Archie G. Quiñones

Updated on January 14, 2022

Comments

  • Archie G. Quiñones
    Archie G. Quiñones over 2 years

    How exactly can you add Margin in Jetpack Compose?

    I can see that there is a Modifier for padding with Modifier.padding(...) but I can't seem to find one for margins or am I blind?

    Someone guide me please.

    Thank you very much.

  • Marcin Orlowski
    Marcin Orlowski almost 4 years
    You cannot consider margin and padding as being the same.
  • nglauber
    nglauber almost 4 years
    I had a long discussion with Adam Powell and Leland Richardson from UI toolkit, and quoting Leland: "realistically, “padding” is actually just “spacing”... So if the guy responsible to the Compose compiler/runtime is saying that, I can say so ;)
  • Marcin Orlowski
    Marcin Orlowski almost 4 years
    This silly argument, because a margin is the space around an element and padding refers to the space between an element and the content inside it. One can contribute to i.e. widget clickable are, the other will not. So yes, visually it can be considered just spacing but different type of hence not functionally equivalent.
  • nglauber
    nglauber almost 4 years
    As you can see in my answer above, the first padding/spacing is acting like a margin. Then, I'm adding a border and a background. Then I'm adding another padding which acting like a padding that we're familiar with on the current UI framework. If you add a clickable modifier in this same sample, you'll notice that the area outside of the background/border is not clickable. That's why I'm saying that padding and margin are the same thing, depending where you're using it.
  • CommonsWare
    CommonsWare almost 4 years
    @MarcinOrlowski: "because a margin is the space around an element and padding refers to the space between an element and the content inside it" -- in Compose, effectively there is no "element" in the way that you are thinking. FWIW, this post summarizes the Slack thread that nglauber refers to and has a link to that thread, if you are interested in reading the original discussion.
  • Archie G. Quiñones
    Archie G. Quiñones almost 4 years
    I still don't get it though. So If I have a button, where I wanted to add margin to. do i just add padding to it? or do I do something like Container(modifier = Modifier.padding(16.dp) ) { Button() }??
  • nglauber
    nglauber almost 4 years
    Just add a padding to the Button's modifier. That's why I'm saying that you think about "padding" as "spacing". And if you want the "old padding" effect on a Button, you can add a padding to the Text's modifier (the Text assigned to the "text" Button parameter).
  • Archie G. Quiñones
    Archie G. Quiñones almost 4 years
    I see... so in other words, if I want to add padding ("old padding") to my button, I cant simply do Button(text = "Click Me").. rather i have to do Button(children = Text("Click Me, modifier = Modifier.padding(16.dp))). correct?
  • nglauber
    nglauber almost 4 years
    Kinda... To add a padding to the "content of your button"(which means, the text), you can use Button(text= { Text("OK", modifier=Modifier.padding(16.dp)) }, onClick={}). Notice the text property is a composable.
  • Archie G. Quiñones
    Archie G. Quiñones almost 4 years
    Ok that make sense but how about Widgets that doesn't accept a single Widget like TopAppBar, doing TopAppbar(modifier = Modifier.padding(16.dp)) { ... } add white space around the AppBar instead of adding it to its width and height. TopAppBarcan have children from title, navigationIcon, action, etc. Who would the have the padding?
  • Jono
    Jono over 3 years
    Can you reference a dimens value for the padding value?
  • ericn
    ericn over 3 years
    This is insane!
  • YaMiN
    YaMiN over 3 years
    So basically it's like a Photoshop layer and modifiers are blending options!
  • Booger
    Booger almost 3 years
    I am still a little confused about Modifiers and thanks for this interesting example. I had no idea about this.
  • Nicolò Parolini
    Nicolò Parolini almost 3 years
    What about textField? Its text is not a composable, so cannot add a padding there. At the same time its background is defined not as a modifier but as a parameter "shape" which is applied before modifiers no matter what. Old padding would include the background shape, whereas margin would not. Now I only got margin, and cannot move the text around (I need for the text to sit Xdp to the right of the CircleShape start).
  • reavcn
    reavcn almost 3 years
    Although there are no visual differences, the bounding boxes for each view won't reflect the visible situation, as padding is contained within the view. The way I see it, this was a poor choice made by the Compose team
  • Eaweb
    Eaweb over 2 years
    I know I got here late, but for the button widget, there's a contentPadding property that works like padding in css.