Should be a simple one.
When I pull image.getDrawable().getIntrinsicWidth() I get a value larger than the source image width. It's X coordinate is returning 2880 instead of 1920 which is 1.5 times too big?
I wondered wether the ImageView having a scaleType of "center" effected it but, according to the documentation:
"Center the image in the view, but perform no scaling."
Here is the source:
<ImageView
android:id="#+id/backgroundImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/background"
android:scaleType="center"/>
You said the drawable is from your /res folder. Which folder is it in?
/res/drawable
/res/drawable-mdpi
/res/drawable-hdpi
etc..
And what is the density of the device you are testing on? Is it a Nexus S with general density of 240dpi? Because if your source drawable is located in the drawable-mdpi folder and you are testing on a 240dpi device, then the Android system will automatically scale the drawable up by a factor of 1.5 so that the physical size will be consistent with the baseline device density at 160dpi.
When you call getIntrinsicWidth() what is returned is the size the drawable wants to be after Android scales the drawable. You'll notice that 2880 = 1920 * 1.5
If you placed the drawable in /res/drawable the Android system treats those drawables as meant for mdpi devices, thus the upscaling in your Nexus S. If this was meant for hdpi screens and you do not want this to upscale then try placing it in drawable-hdpi
Have you tried to multiply height and width by density:
getResources().getDisplayMetrics().density
Is your drawable in ressources or download from the web? If it is downloaded, you have to give it the density:
DisplayMetrics metrics = new DisplayMetrics();
getContext().getWindowManager().getDefaultDisplay().getMetrics(metrics);
Resources r = new Resources(getContext().getAssets(), metrics, null);
BitmapDrawable bmd = new BitmapDrawable(r, bitmap);
Check if it is returning the value of it's displayed size, which is not it's actual size. For example, a 50x320px banner ad on a traditional 800x480 phone displays as 75x480.
Should be able to compare against density (or your eyes!) to see what it is doing.
This is probably going to be nothing to with the issue you're having, but just for kicks I'll suggest it to be sure anyway: Are you specifying android:minSdkVersion in your manifest?
Only reason I mention this is because for a while I wasn't doing so in a project, and I learned that this screws the screen density up and caused all sorts of strange problems.
Related
There are so many material on densities, multiple screen support, so many questions on SO, but I still have not got it.
My goal is simple: display a bitmap as large as available space for ImageView. I need BitMap as I will do some operations on it.
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/figureView" />
I will have some pictures to be used in the bitmap. I will place them in drawables directory. I will reference them with R.drawable.pictureX. I will use Picasso to load them and scale them:
Bitmap bitmap = Picasso.with(getContext()).load(resourceId).resize(w, h).get();
The unclear part for me is all those xxhdpi folders and Android heuristic to select the best.
When a documentation says that Android will automatically scale the image does it apply to my case? I do not want to scale already scaled pictured.
How many dpi variants shall I store in my case and where? Shall I have single file in no-dpi folder or shall I create picture variant for each dpi folder?
How can I determine a dimension for picture resource? It is easy for icons: for example 24x24 dpi and then multiple it with DPI formula. But I want to cover complete screen height. A chapter Configuration examples lists: 240x320 ldpi, 320x480 mdpi, 480x800 hdpi, 720x1280 mdpi, 800x1280 mdpi etc. There are no screen size qualifiers for resources.
Thanks for clarification.
I realized that in fact it is easy to find out Android behavior. I just need each DPI variant different so I can distinguish between them. I put a text with DPI name and pixel resolution inside each picture.
There is a sample GitHub Test DPI project. It has two ImageViews. The first is initialized from XML and Android does scaling. The second is a placeholder that I fill with a BitMap. I entered 200dp as its size and that was correct. Pixel size of MDPI = size in dp.
What I found is logical. Android does not know anything about my intentions. It just selects the best available resource for current DPI.
Nexus 5x uses XXHDPI by default, Samsung SIII Mini uses HDPI. If I delete their default DPI folders, they down-scale higher available variant: XXXHDPI and XHDPI. If I delete all variants except NODPI, this will be used.
And finally if I change the dimensions of ImageView dynamically loaded from source code to 300dp, then it will be scaled and look ugly. Android cannot know at decodeResource execution that I will scale it later and that there is a better resource available.
What remains unknown is how to find out dimensions of picture that fits the screen.
Java:
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inScaled = false;
Bitmap figureBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_test, opt);
ImageView imageView=(ImageView) findViewById(R.id.testView);
imageView.setImageBitmap(figureBitmap);
Activity:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_test" />
<ImageView
android:id="#+id/testView"
android:layout_width="200dp"
android:layout_height="200dp" />
Update 30th august
Original picture: 230x541 px, loading with
Picasso.with(getContext()).load(R.drawable.amalka).into(target)
stored in nodpi, loaded as 230x541 px Bitmap
stored in xxhdpi, loaded as 230x541 px Bitmap
1.Android will automatically scale image in case when you provided image for one screen dencity and there is no such image for another one. e.g. if you add your image only in drawable-xxxhdpi folder, Android will generate images for xxhdpi, xhdpi screen dencities etc.
2.You can save your image in one folder drawable-xxxhdpi and let Android make the downscale, if you don't like the result you can create images for different dencities on your own.
name dencity scale
mdpi 160dpi x1
hdpi 240dpi x1.5
xhdpi 320dpi x2
xxhdpi 480dpi x3
xxxhdpi 640dpi x4
3.You can define dimensions of your images based on size of you ImageView and dpi scale. For example if your ImageView has width 80dp and height 40dp then your image for drawable-mdpi folder should have size 80x40px because mdpi is a baseline dencity, for drawable-hdpi then you need to have image 120x60px (scale is 1.5) etc. For drawable-xxxhdpi your image will be 320x160px.
If you want your image to fit all the screen on all devices you can use parameter android:scaleType="centerCrop", it will make the image take all the space but little part of image can be hidden depending on screen aspect ratio. You can also try to specify image resorces based on shortest dimension of the available screen area, e.g. drawable-sw720dp. Read more about this here.
I have a bitmap with the dimensions of 537 * 233. This is displayed in my fragment.
I am calculating the height of this bitmap through code as well.
I came to know that simply using,
image.getHeight() will always return 0.
Then I found that putting the same in overridden method onGlobalLayout() will give the actual height.
I did that. See my SO post for link.
Now the height I am getting is 155.
I also tried getting the height with,
BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(R.drawable.chart);
imgHeight = bd.getBitmap().getHeight();
Again the height I am getting is 155.
According to the above dimensions, the height should be 233.
I am seeing the same height in emulator too.
Why is the difference and/or what I consider to be its actual height ?
UPDATE:
ok, my chart was in drawable-hdpi and the density of my device is 160. So when I put the chart image in drawable folder, I got the correct height. But then if the chart height is fixed (233), why in some devices I am getting the chart height big enough to overlap my bottom timeline. Although I know a bit that this may be because of approximate values and not accurate values (density, resolution) that is causing the in-differences. But then, Any ideas how to fix that ?
First you know mdpi = 1, hdpi = 1.5 and xhdpi = 2.
Lets say you have an image in mdpi folder with width = 100px.
On mdpi device the image width will be 100x1 = 100px,
On hdpi device 100x1.5 = 150px,
On xhdpi device 100x2 = 200px.
if you dont have the image in hdpi or xhdpi folders the android system will scale them.
So when you have an Image in hdpi folder and you run the app on medium density device (mdpi), the android will scale down the image by 1.5. 233 / 1.5 = 155.
The same will happend if run the app to hdpi device you will get an image with ~310 width.
So, to avoid the scaling i suggest to put the image in drawable-nodpi folder (the images in this folder will not scaled by android system).
PS: if you put the image in drawable folder and run in mdpi device the image will not scaled because drawable folder = drawable-mdpi
I am using image say 85x85 px (putting this image in drawable-mdpi)
and if i am displaying this image of 85x85 px on [320x480]mdpi screen size device it looks good,
but while displaying this image on [480x800]mdpi device it looks very small.
I wants to know how can i resize this image of (85x85 px) so that it works fine for the device having screen width and height of 480x800, mdpi.
You have to set the image size in the xml in dp. This post is really helpful.
Consider MDPI image(let say 85x85) as baseline Create images as follow
FOLDER ImageSize Percentage
LDPI 64x64 75% of baseline
MDPI 85x85 100% BASELINE
HDPI 127x127 150% of baseline
XHDPI 170x170 200% of baseline
The better solution for this is to produce LDPI,MDPI,HDPI,XHDPI,XXHDPI sized images and place it inside the corresponding folders.
Put the image in /drawable, and define the size of the image in your XML as 85dp, it will then be scaled for LDPI/HDPI/XHDPI/XXHDPI and god forbid XXXHDPI.
However, the better solution would to produce HDPI(128px)/XHDPI(170px)/XXHDPI(255px) version of the graphics and put them in /drawable-hdpi, /drawable-xhdpi, /drawable-xxhdpi respectively. This way you can provide the best experience for your users.
[Edit]
"dp" is Android's way of defining physical size of an UI objects, so a button of 48x48dp will have roughly the same physical dimension even when run on screen sizes between 240x320 to 1080x1920, for more information check Android developer site's Supporting Multiple Screens.
[Edit 2]
For images on canvas you can use this to calculate the scaled size of the image:
DisplayMetrics dm = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(dm);
int newSize = (int)(85 * (dm.densityDpi / 160f));
I know there are N threads about this question, but I still don't know how to apply width and height for Widgets (buttons, images) on Android.
I have read this: http://developer.android.com/guide/practices/screens_support.html
and many other threads, but I don't understand it.
How am I supposed to calculate dpi for a button?
Am I need to know the dpi of the device? (Wikipedia list):
http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density
But there are plenty other devices with different dpi's!
I have a design in photoshop (800x480), and a button (290x65). I have saved and imported the image button in the newly created 'drawable' folder in my android project. In XML (layout) I inserted the ImageView with the imported button image.
<ImageView
android:id="#+id/btnNewImage"
android:layout_width="210dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="7dp"
android:src="#drawable/new_image" />
The image inserted is completely different, it's much more bigger. How am I supposed to calculate the exact width and height values for Android sizes?
If you need to know the dpi of a device, use the following snippet:
int dpi = getResources().getDisplayMetrics().densityDpi;
If you want to convert from dp to pixels:
int px = (int)(dp * getResources().getDisplayMetrics().density + 0.5f);
If you want to convert from pixels to dp:
int dp = (int)(px / getResources().getDisplayMetrics().density + 0.5f);
To get your image to show up as the right size, you need to put it in the correct "drawable" folder. For example, if you have an icon that is 48x48 pixels, it should go in drawable-mdpi. Ideally, you should create graphics for each of the folders so that Android can pick the best one based on the screen size and resolution.
I'm using the following guidelines for my icons (which I gleaned from somewhere now forgotten); you can extrapolate on these to figure out what pixel dimensions you need:
Recommended drawable sizes - to match size of launcher icon, about 3/8"
36x36 - low
48x48 - med
72x72 - high
96x96 - extra high
I need drawable resources for different resolutions, such as 320x480, 800x480, 854x480, 800x600
1024x600, 1024x768, 1024x800. It is a game and the scaling of bitmaps is inacceptable, coz they are very sensitive to it. dpi dependent folders and combination with screen sizes(which are deprecated but no other way to set drawable for large screens with same resolution and differend dpi) are not enaugh. How to distinguish graphics for 1024x600 and 1024x768 for example?
It is so sad to stop use mechanism of auto picking resources and switching to manual loading from assets.
any ideas?
I'm usually using 4 resource folders for drawables:
drawable-mdpi for 320x480
drawable-hdpi for 480x800 and 480x854
drawable-large-hdpi for 600x1024, 768x1024 and so on
drawable-xlarge-mdpi for 800x1280
These are just enough in my mind. Also, you don't need to worry about different drawable resources for, in example, devices with 800x480 and 854x480 screen sizes: you can specify an offset on the edges of your screen equal to 27 pixels and center your game on the screen. Hope this helps.
If you want a pixel perfect fit you could always load the background at runtime via a simple method:
private void setBackgroundImage() {
DisplayMetrics dm = getResources().getDisplayMetrics();
int screenWidth = dm.widthPixels;
int screenHeight = dm.heightPixels;
// TODO: Conditional Structure to apply the right drawable
// ressource to be applied in the background
}
After you've acquired the resolution of the display you can apply the appropriate background via the setBackgroundDrawable method.