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"?
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);
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)
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.
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.
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()
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
Related
When I tried same text size on top different resolution bitmaps on a canvas. Same text size looked small on a bigger resolution and bigger on a small resolution image. Please Help me understand this.
You need to set proper text size for your Paint, that accounts for density. Paint.setTextSize(float), takes in a float value. You need to ensure that this is not a constant value, but one that accounts for density.
How to get the density? You get that information from DisplayMetrics.scaledDensity or DisplayMetrics.density. Once you have this value, multiply this with the fontSize and set that value as the text size. Somthing like the below.
Paint.setTextSize(density * 10f);
This way a text with 10f font size will look the same in all devices with varying densities. You can find more information on density and scaledDensity here: http://developer.android.com/reference/android/util/DisplayMetrics.html#scaledDensity
This is way you can make all text uniform size in all device.
canvas.drawText(hourText, getPx(TEXT_SIZE, activity), getPx(TEXT_SIZE / 3, activity), nPaint);
public static int getPx(int dp, Activity activity) {
DisplayMetrics metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
float logicalDensity = metrics.density;
return (int) Math.ceil(dp * logicalDensity);
}
when declaring some element (let's say a Button) and giving it some width and height (let's say 200dp) from the XML file, I got certain result when running, although when make the same steps but Programmatically I got much smaller width and height, and this case happens only with me in Nexus tablets.
If you set the size of a View programmatically, many times pixels are taken as an argument. You will need to convert your desired size in DPs to pixels first, and use those to set the width or height of your element:
float dp = 200;
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
See the API-docs of the specific Views for infos about what kind of dimensions are taken as an argument.
The developers website simply states that getHeight() will return the bitmap's height, but can someone tell me that is in pixel unit or dp unit?
It's pixel. In Java code you usually work with pixels, e.g. a view's width and height.
After Hours of Experimenting I found that it actually return height in dp units.You can verify it by changing the device screen in emulator.
bitmap.getWidth() returns width in dp unit or densitiy.
To get dpi (density per inch) for a device, use
float dpi = context.getResources().getDisplayMetrics().density;
To convert dp to px
float px = dp * dpi;
and to convert px to dp
float dp = px/dpi;
If you read on how android deals with views this not clear at all. See "Supporting Multiple Screeens". After reading that document I have come to the conclusion that "it depends." (And I'm still guessing as I have not verified my analysis.) If the View was declared with size "wrap_content", "fill_parent", or "dp" then you get "dp", otherwise you get pixels. If you used "dp" then scaling to pixels is achieved by multiplying by
getResources().getDisplayMetrics().density
For 160 dpi screen, this returns 1.0; for 320 pi screen this returns 2.0.
Dividing by getResources()....density.
In my app I create a canvas and add some bitmaps on it. The problem is that the objects are adding why touch the screen. So on one screens they appear on the middle on different the same, but their position in pixels are different.
I mean that I got tablet and smartphone. When I touch one the object appear on both devices (multiplayer) but its not in the same place, because its passing the position by x and y.
If someone understand what I mean, can you help me?
Probably it must have something common with counting the ratio.
I am guessing the problem you are having is that the screens are different resolutions and you are passing pixel data. You will need to use dp values and before sending them convert the dp to pixel values. On the receiving device you will need to convert the pixel values being sent back to dp on the given device. Use the methods below for the conversion.
To Convert DP to Pixels:
final float scale = getResources().getDisplayMetrics().density;
int pixelValue = (int) (DESIRED_DP_VALUE * scale + 0.5f);
To Convert Pixels to DP:
final float scale = getResources().getDisplayMetrics().density;
int dpValue = (int) ((DESIRED_PIXEL_VALUE) - 0.5f / scale);
The call to getDisplayMetrics().density is what will give you a scale value based on the current device. The dp value is meant to be density independent.
How do you define the metrics? If you are using pixels, use a density independent solution:
public int GetDipsFromPixel(float pixels)
{
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
return (int) (pixels * scale + 0.5f);
}
And use it like this in you class:
textView.setHeight(GetDipsFromPixel(50));
This way the the height of the textview will be the same dps on both devices, even if their resolution is different.
This question already has answers here:
How do you make layouts for several Android screen sizes?
(3 answers)
Closed 9 years ago.
I am developing the app in 320*480. How do make the app to be run in 480*854 screen? When i tried to run in 480*854 screen, the app original design looks like small. Do I want to create separate layouts for each screen in android? If so, please provide me the sample hint to proceed.
I have implemented my own way of Handling Multiple Screen Resolutions.
You could certainly avoid this problem by setting LayoutParams at run time in terms of Percentage
The Problem occurs only with Views/Layouts that have some constant width or height lets say 280dp. Solution is quite simple if we programmatically set Layout Params of our Views/Layouts in terms of Percentage and only use constant width or height where necessary, elsewhere try to use match_parent to fill up empty space or use weights and define every View relative to other Views this will help your layout to look good in almost every screen resolutions
Here is a sample xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/mLayout"
android:layout_width="280px"
android:layout_height="300px" />
</RelativeLayout>
Notice: I have used px for fixed sized layout's width/height because in LayoutParams layoutParams = new LayoutParams(int width, int height); the width and height take value as pixels
Here is an example code of setting width and height in terms of percentage
final ViewTreeObserver mLayoutObserver = mLayout.getViewTreeObserver();
mLayoutObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
DisplayMetrics metrics = getResources().getDisplayMetrics();
int deviceWidth = metrics.widthPixels;
int deviceHeight = metrics.heightPixels;
float widthInPercentage = ( (float) 280 / 320 ) * 100;
float heightInPercentage = ( (float) 300 / 480 ) * 100;
int mLayoutWidth = (int) ( (widthInPercentage * deviceWidth) / 100 );
int mLayoutHeight = (int) ( (heightInPercentage * deviceHeight) / 100 );
LayoutParams layoutParams = new LayoutParams(mLayoutWidth, mLayoutHeight);
mLayout.setLayoutParams(layoutParams);
}
});
Now might be some people are wondering what is happening here
float widthInPercentage = ( (float) 280 / 320 ) * 100
Let me explain 280 is the width of my LinearLayout and 320 is the width of my device screen(on which i'm developing), i know currently i'm testing on a device having resolution 320 x 480, what i'm doing is calculating how much area my layout is covering in terms of percentage and then
int mLayoutWidth = (int) ( (widthInPercentage * deviceWidth) / 100 )
here i'm calculating the new width for my layout according to the screen resolution and by this way your Views/Layouts will look exactly the same on every screen resolution.
Conclusion: If you need to set some constant width/height for your Views/Layouts always set value in px in layout file (i.e xml) and then programmatically set LayoutParams.
A Suggestion for Google Android Engineers, i guess you guys should seriously think of changing the dp/dip units to percentage
for that you can make your layout dynamic with reference to available width and Height of the device
Display mDisplay= activity.getWindowManager().getDefaultDisplay();
int width= mDisplay.getWidth();
int Height= mDisplay.getHeight();
set your layout in terms of perecentage with reference to avail size
Mr. Babar,
I think you should follow the below formula instead of calculating like
float widthInPercentage = ( (float) 280 / 320 ) * 100;
float heightInPercentage = ( (float) 300 / 480 ) * 100;
int mLayoutWidth = (int) ( (widthInPercentage * deviceWidth) / 100 );
int mLayoutHeight = (int) ( (heightInPercentage * deviceHeight) / 100 );
I would suggest like if you take this as follows:
int baseWidth=320;
int baseHeight=480;
int mLayoutWidth = (int) ( (280* deviceWidth) / baseWidth);
int mLayoutHeight = (int) ( (300* deviceHeight) / baseHeight);
Also this is going to work for Views and not for text-sizes;
In Android, you don't go by the the absolute resolution, but rather focus on the screen density.
And yes you might need to create different layout to support various densities and screen sizes. In general there are four densities supported by Android (low, medium, high, extra high)
I suggest you read Supporting Multiple Screens for Android. I think it will help you achieve what you need to do. It has various sections on Designing alternative layouts and drawables and other useful info related to supporting multiple screen resolutions.
hi welcome to stack overflow...
From version 1.6 onward, Android supports multiple screen resolutions and densities separated into three classes:
Small: devices with a screen size smaller than the T-Mobile G1 or Samsung I7500, like the HTC Tattoo
Normal: devices with a screen size roughly the same as the G1 or I7500.
Large: devices with a screen size larger than the G1 or I7500 (such as a tablet-style device.)
Developers can control if and how apps appears to devices in each group by using tools introduced in the Android framework APIs and SDK. Details on implementation can be found in the Android Dev Guide article Supporting Multiple Screens. you may refer this link MultiResolution
or may use
Display displayparm= activity.getWindowManager().getDefaultDisplay();
int width= displayparm.getWidth();
int Height= displayparm.getHeight();