How to get widget size in pixels?
I am using Note 3 smartphone, I took screenshot and calculated manually, should be 1020px x 316px (+-5px), 4x1widget (resizable).
I tried the code bellow, but I get wrong results:
minW_dp=324dp, maxW_dp=439dp, minH_dp=69dp, maxH_dp=88dp.
minW=782px, maxW=1060px, minH=167px, maxH=213px.
How to get real size of widget in pixels?
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions)
{
int minW_dp = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int maxW_dp = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
int minH_dp = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
int maxH_dp = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
int minW = dpToPx(minW_dp, context);
int maxW = dpToPx(maxW_dp, context);
int minH = dpToPx(minH_dp, context);
int maxH = dpToPx(maxH_dp, context);
bitmap = Bitmap.createBitmap(minW, maxH, Config.ARGB_8888);
}
public static int dpToPx(int dp, Context context)
{
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
int px = Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
return px;
}
Your dpToPx calculation is wrong. You need to change it from:
int px = Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
to
int px = Math.round(dp * displayMetrics.density);
If you read the Docs it gets obvious why your calculation couldn't work. (Note: DisplayMetrics.xdpi seems to be messed up on some devices as well, see this post)
Following what displayMetrics.xdpi represents:
The exact physical pixels per inch of the screen in the X dimension.
But you don't wanna get the pixels per inch of your screen. You wanna get the scale-factor, that's where displayMetrics.density comes into play:
The logical density of the display. This is a scaling factor for the
Density Independent Pixel unit, where one DIP is one pixel on an
approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen),
providing the baseline of the system's display. Thus on a 160dpi
screen this density value will be 1; on a 120 dpi screen it would be
.75; etc.
Note: The Note 3 is a xxhdpi device and thus has a scale-factor of 3.0 (480dpi).
Edit
An other way to calculate the dp->px:
(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, maxH_dp, context.getResources().getDisplayMetrics());
Related
I have to support android devices with screen resolution 1280*800(in dp)(KitKat) and 1280 * 752(dp)(Lollipop). The first one is a 10.1 inch tablet and second one is 9.6 inch tablet.
I am using same layout for all device and using externalized dimension to adjust layout for different screen.
But I am not able to separate the device using "values-sw720dp" and "values-sw800dp". If I use sw800dp both of them use the dimen value from sw800dp dimen folder.
How can I give separate dimension for the two devices?
Get your device's screnn inches programmatically and appy dimension
public static double getDeviceInches(Activity activity) {
DisplayMetrics metrics = getMetrics(activity);
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
float widthDpi = metrics.xdpi;
float heightDpi = metrics.ydpi;
float widthInches = widthPixels / widthDpi;
float heightInches = heightPixels / heightDpi;
return getDiagonalInches(widthInches, heightInches);
}
private static double getDiagonalInches(float widthInches, float heightInches) {
double diagonalInches = Math.sqrt((widthInches * widthInches) + (heightInches * heightInches));
float roundedValue = (float) Math.round(diagonalInches);
return (double)roundedValue;
}
//From this, we can get the information required to size the display:
private static DisplayMetrics getMetrics(Activity activity) {
DisplayMetrics metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
return metrics;
}
public static int convertDpToPx(Context context, int value) {
// Get the screen's density scale
final float scale = context.getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale(0.5f is for rounding up value) (arrowWidth is 50dp)
int pxValue= (int) (value * scale + 0.5f);
return pxValue;
}
Put your above code in utility class and call getDeviceInches method from your acitivty or fragment class
Suppose I have a value say :-
360dp for a device that is:
Resolution: 1280x800
sw800dp
mdpi
Now I know this dp value works well for the device. How do I calculate the dp value for a device that is:
1024x600
sw600dp
Edit 1:
Maybe I didn't make myself clear. I know what the width must be in dp for a give device typeA with certain resolution R1. How do I calculate the dp value should be for another device typeB with resolution R2?
mdpi
and similarly for a device that is:
2560x1600
sw800dp
xhdpi
I guess what I want to know is how does the math work. What would be the way to calculate the dp value to put in different values files.
i think below class is complete solution for your present as well as futer problems ,
public class DisplayUtil
{
private static int DisplayWidthPixels = 0;
private static int DisplayheightPixels = 0;
private static void getDisplayMetrics(Context context)
{
DisplayMetrics dm = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
DisplayWidthPixels = dm.widthPixels;
DisplayheightPixels = dm.heightPixels;
}
public static int getDisplayWidthPixels(Context context)
{
if (context == null)
{
return -1;
}
if (DisplayWidthPixels == 0)
{
getDisplayMetrics(context);
}
return DisplayWidthPixels;
}
public static int getDisplayheightPixels(Context context)
{
if (context == null)
{
return -1;
}
if (DisplayheightPixels == 0)
{
getDisplayMetrics(context);
}
return DisplayheightPixels;
}
public static int px2dip(Context context, float pxValue)
{
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
public static int dip2px(Context context, float dipValue)
{
if (context == null)
{
return 0;
}
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
public static int px2sp(Context context, float pxValue)
{
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
public static int sp2px(Context context, float spValue)
{
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
}
ex. just you have to call DisplayUtil.Method-Name !
A set of six generalized densities:
ldpi (low) -120dpi,
mdpi (medium) -160dpi,
hdpi (high) -240dpi,
xhdpi (extra-high) -320dpi,
xxhdpi (extra-extra-high) -480dpi,
xxxhdpi (extra-extra-extra-high) -640dpi.
If running on mdpi device, 150x150 px image will take up 150*150 dp of screen space.
If running on hdpi device, 150x150 px image will take up 100*100 dp of screen space.
If running on xhdpi device, 150x150 px image will take up 75*75 dp of screen space.
And here we go... We have a online calculator...
https://pixplicity.com/dp-px-converter/
I had a similar problem, so tried this and it worked.
I have known the difference among DP, SP and PX. And after searching this topic, I found nothing satisfying me completely. Maybe this post is a duplicate, but I still want to know what is the formula of converting from DP to PX, and DP to SP, from SP to PX, from PX to SP, from SP to DP, from DP to SP? I have known some codes to do this, but they are imperfect.
DP to PX:
public static int dpToPx(float dp, Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}
SP to PX:
public static int spToPx(float sp, Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());
}
DP to SP:
public static int dpToSp(float dp, Context context) {
return (int) (dpToPx(dp, context) / context.getResources().getDisplayMetrics().scaledDensity);
}
The accepted answer is missing a few useful conversions.
SP to PX
float sp = 20;
float px = sp * getResources().getDisplayMetrics().scaledDensity;
or
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
PX to SP
float px = 70;
float sp = px / getResources().getDisplayMetrics().scaledDensity;
DP to PX
float dp = 20;
float px = dp * getResources().getDisplayMetrics().density;
or
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
PX to DP
float px = 70;
float dp = px / getResources().getDisplayMetrics().density;
Notes
The floats I chose above (20 and 70) were arbitrary values. You can plug in different numbers if you like.
px refers to pixels. The number of pixels that a device has per inch of screen space is called the density.
dp means density-independent pixels. That is, no matter what device is used, the actual size should be the same. For example, if I set a view to be 100 dp wide, it will have the same width on a new high density phone as it does on an old low density phone. (If I had set the width to 100 px, on the other hand, it would appear large on a low density phone and small on a high density phone.) Density is measured in dots per inch (DPI). The formula is px = dp * density. So you just multiply or divide by the density to convert between px and dp.
sp means scale-independant pixels. It is just used for fonts, not views. It is similar to dp except it also factors in the user preferences. This density with user preferences taken into account is known as scaled density. Setting a TextView font to a size of 30 sp, for example, will make the text generally appear to be the same physical size on all devices. However, your grandmother may have her preferred font size maxed all the way up in her phone settings, so 30 sp text will look bigger on her phone than it does on yours. The formula is px = sp * scaledDensity.
Meaning of DP and SP
DP to SP conversion is not generally useful
For converting Dimension to Integer or Pixel you need to use "getDimensionPixelSize(R.dimen.your_dp_value)" function, Like...
Make a value in dimens.xml
<dimen name="padding_10">10dp</dimen>
Now for That value in pixel or integer you can use as like below:
int sizeInPixel = context.getResources().getDimensionPixelSize(R.dimen.padding_10);
For kotlin I created an extension function:
fun Number.spToPx(context: Context) = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, this.toFloat(), context.resources.displayMetrics).toInt()
You can use it like 16.spToPx(context) or 16.5.spToPx(context)
(I place such functions in a KotlinExtensions.kt file)
You can write a method, that doesn't need context or resources:
public static int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
public static int spToPx(int sp) {
return (int) (sp * Resources.getSystem().getDisplayMetrics().scaledDensity);
}
By analogy, other quantities can be converted.
According to TypedValue#applyDimension source code and take advantage of Kotlin extension:
val Float.toSp get() = this * Resources.getSystem().displayMetrics.scaledDensity
Other extensions from link
val Float.toPx get() = this * Resources.getSystem().displayMetrics.density
val Float.toDp get() = this / Resources.getSystem().displayMetrics.density
Well, i been trying to figure out, is there a simple way to pass from dp or milimetres or even inches to px. (like: 6dp would be 20px)
It seems everything is usually done in px but i want to use these in orther to keep the proportions in different screens and have a rough sense of how big is going to be (guessing with pixels feels really...bothering)
Thanks in advance and sorry if the question is too vague.
There is no way to convert milimetres or even inches to px programmatically. If you want to support different screens, you can follow the document here.
To convert dp to px, you can also use the following method:
/**
* Convert dp to px.
* #param context
* #param dp the input dp.
* #return the output px.
*/
public static int dpToPx(Context context, int dp) {
float density = context.getResources().getDisplayMetrics().density;
return (int) (dp * density + 0.5);
}
Update:
Here is how to get a device's width and height pixels:
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
I searched this question, and almost all of the answers are like this:
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
But the official document says widthPixels is The absolute width of the display in pixels. I run the code above on my Nexus 5, and the width equals 1080. Obviously it is an Pixel value. Is there anything I missed? How can I get a dip value of the screen?
you should convert the result to dips, like:
private int pixelsToDips(int pixels)
{
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pixels / scale + 0.5f);
}