ChatGPT解决这个技术问题 Extra ChatGPT

Android and setting width and height programmatically in dp units

I'm doing:

button.setLayoutParams(new GridView.LayoutParams(65, 65));

According to the docs the units for the width and height (both 65 in the above) are "pixels". How do you force this to be device independent pixels, or "dp"?


R
Robby Pond

You'll have to convert it from dps to pixels using the display scale factor.

final float scale = getContext().getResources().getDisplayMetrics().density;
int pixels = (int) (dps * scale + 0.5f);

The correct conversion is (int) (dps * scale + 0.5f). This is the formula we use throughout the framework.
The formula is in the docs. For further reading, go to section 3 of developer.android.com/guide/practices/…
@RomainGuy, can you please add a utility function to the API to convert from dp to px? Thanks.
what is dps here? im getting "dps cannot be resolved to a variable" error? what type of "dps" need to declare??
The "dps" variable is the input value that you want to convert.
C
Cassie

I know this is an old question however I've found a much neater way of doing this conversion.

Java

TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 65, getResources().getDisplayMetrics());

Kotlin

TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 65f, resources.displayMetrics)

Well done for finding out how to do this. I'm not a fan of repeating a formula in several places! Thanks.
If not, then create function with the formula
@Kenobi It does the conversion for you from DP to PX. The 65 above is the DP value you want converted to PX
This should be the accepted answer, not the current one where these number (0.5) coming magically from no where
@Johny19 The 0.5 is not magic. It's just how to round a floating point number to the nearest integer instead of truncating it. See my comment on Robby Pond's answer for more detail.
G
Gowthaman M

simplest way(and even works from api 1) that tested is:

getResources().getDimensionPixelSize(R.dimen.example_dimen);

From documentations:

Retrieve a dimensional for a particular resource ID for use as a size in raw pixels. This is the same as getDimension(int), except the returned value is converted to integer pixels for use as a size. A size conversion involves rounding the base value, and ensuring that a non-zero base value is at least one pixel in size.

Yes it rounding the value but it's not very bad(just in odd values on hdpi and ldpi devices need to add a little value when ldpi is not very common) I tested in a xxhdpi device that converts 4dp to 16(pixels) and that is true.


v
vine'th

Looking at your requirement, there is alternate solution as well. It seems you know the dimensions in dp at compile time, so you can add a dimen entry in the resources. Then you can query the dimen entry and it will be automatically converted to pixels in this call:

final float inPixels= mActivity.getResources().getDimension(R.dimen.dimen_entry_in_dp);

And your dimens.xml will have:

<dimen name="dimen_entry_in_dp">72dp</dimen>

Extending this idea, you can simply store the value of 1dp or 1sp as a dimen entry and query the value and use it as a multiplier. Using this approach you will insulate the code from the math stuff and rely on the library to perform the calculations.


Note that the return value is actually an int, so it gets cast to a float.
This is a bad answer because it is fare to be dynamic
R
RickSanchez725

Based on drspaceboo's solution, with Kotlin you can use an extension to convert Float to dips more easily.

fun Float.toDips() =
        TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, resources.displayMetrics);

Usage:

(65f).toDips()

Q
Quick learner

Kotlin Version

val scale: Float = resources.displayMetrics.density
val resizedInDp = (stream.videoWidth * scale + 0.5f).toInt()

Usage:-

val params: ViewGroup.LayoutParams = yourLayout!!.layoutParams
            val scale: Float = resources.displayMetrics.density
            params.width = (widthDp * scale + 0.5f).toInt() // dp to px
            params.height =
                (heightDp * scale + 0.5f).toInt() // setting height according to aspect ratio
            yourLayout!!.layoutParams = params