Valeriy Katkov
Valeriy Katkov

Reputation: 40662

How to convert Dp to pixels in Android Jetpack Compose?

Most of Jetpack Compose API uses Dp as a dimensions unit, but sometimes a pixel value is required. How can I convert a dp value to px? Just for an example there's graphicsLayer() modifier that accepts translationX/Y arguments in pixels.

Upvotes: 90

Views: 78326

Answers (4)

Vishal A.C
Vishal A.C

Reputation: 13

With some little tweaks to @Oliver Metz's solution -

@Stable fun Dp.toPx(): Float = this.value * Resources.getSystem().displayMetrics.density

this is a clean way to convert dp to px without needing the function to be a composable, which makes it a little performant and even allows it to be used outside composables.

also, @Sirop4ik's solution has no benefits, 1. Inlining these converters means the same code is gonna be copied to the call site, increasing app size. This is especially noticeable if u use it a lot. 2. Using a getter instead of a function, this makes the usage like this - 120.dp.toPx as opposed to 120.dp.toPx(). Which doesn't look the way how we use the converters like .toInt(), .toString() etc. More importantly these getters are anyway compiled to functions. for example,

val testVariable: Int get() = 1

fun testFunction(): Int = 1

Is compiled to-

public static final int getTestVariable() { return 1; }

public static final int testFunction() { return 1 }

So, this has no difference.

Upvotes: 1

Sirop4ik
Sirop4ik

Reputation: 5263

I use this approach and there are two advantages:

  1. "inline"
  2. it is variable (not function)
inline val Int.dp: Dp
    @Composable get() = with(LocalDensity.current) { [email protected]() }

inline val Dp.px: Float
    @Composable get() = with(LocalDensity.current) { [email protected]() }

Upvotes: 4

Oliver Metz
Oliver Metz

Reputation: 3798

@Valeriy's answer is definitely the correct way to do it but if you want it slightly less verbose or you have a lot of converting to do you can create extension functions:

@Composable
fun Dp.dpToPx() = with(LocalDensity.current) { [email protected]() }


@Composable
fun Int.pxToDp() = with(LocalDensity.current) { [email protected]() }

This lets you convert your dp straight to px and vice versa.

val dpValue = 16.dp
val pxConverted = dpValue.dpToPx()

val pxValue = 100
val dpConverted = pxValue.pxToDp()

Upvotes: 54

Valeriy Katkov
Valeriy Katkov

Reputation: 40662

There're toPx() and roundToPx() methods defined by Density interface, you can use it like this:

import androidx.compose.ui.platform.LocalDensity

val pxValue = with(LocalDensity.current) { 16.dp.toPx() }

// or

val pxValue = LocalDensity.current.run { 16.dp.toPx() }

Such an expression might look confusing if you're new to Kotlin language so let's break it down and see how it works. toPx() is an extension function of Dp class, you can think of it as a Dp class method. But since toPx() is defined inside Density interface, you cannot use it unless you provide a density as a receiver. And at last you can get the current density from an CompositionLocal named LocalDensity.

Upvotes: 210

Related Questions