2

I am developing a game using a surface panel. I've done a lot of research about how to properly scale and position drawables in the canvas for multiple devices and I came up with a solution that is working fine on phones but has some flaws when I try it on tablets. I am aware that I can use different resources for tablets (and i might end up doing that) but let's assume for now that I don't want to do it, I want to use the same resources for every single different phone in the market.

All the resources that I have are located it in the hdpi folder, and they are properly sized for a 480x800 device.

My approach is similar to the one described here, please take a look on the explanation below, and I would like to know if there is a better solution for this problem!

I have a Galaxy S2 for testing my apps. So my first approach was to manually insert position everything directly in the canvas by trying and finding the best position for everything. Taking the first character position as an example:

draw_x = (float) (19);
draw_y = (float) (279);
canvas.drawBitmap(toDrawBitmap, draw_x, draw_y, null);

When I first tested it in different devices, everything as a mess, out of scale. So digging around I thought about using the density for scaling the resources.

 // I am dividing by 1.5 because my initial positions are on a high density device
 // so when it goes for a medium density it should scale for 0.66 and a small density 
 // for 0.5 of my positions. 
 float scale = getResources().getDisplayMetrics().density /1.5;
 draw_x = (float) (19) * scale;
 draw_y = (float) (279) * scale;
 canvas.drawBitmap(toDrawBitmap, draw_x, draw_y, null);

And at first impression this worked like a charm. It all my characters were in the proper positions. But I noticed that if the device has a different scale widht/height compared to the Galaxy S2 that I am using the problems begin. Although everything was properly positioned part of the image was cut out of the screen, the canvas was calculated larger than the phone screen.

Galaxy S2 is 480x800. My background is also 480x800. When I tested it in the emulator on a small screen resolution 320x480 Android didn't scale my background correctly as I expected it to do so. Instead of scaling it for the right resolution it gave me a background larger than my canvas 320x533.

With some simple math we figure that 320x533 / 480x800 = 0.66. So instead of properly scaling the background in the canvas, it just scaled using the density of the devices.

So my workaround for this problem was the simplest I could think of. I know the resolution of my background, I know the resolution of the phone, so I can calculate the proportion I need and force a resize.

 //Set the proportions for scaling in multiple devices
 public void setProportions(float screenWidth,float ScreenHeight,Bitmap background){

     this.heightProportion = ScreenHeight/background.getHeight();
     this.widthProportion = screenWidth/background.getWidth();

 }  

 public Bitmap scaleBitmaps(Bitmap bitmap) { 
         Bitmap out = Bitmap.createScaledBitmap(bitmap, (int) (bitmap.getWidth() * widthProportion), 
                    (int)  (bitmap.getHeight()*heightProportion), false);         
         return out;
     }

That worked fine for the sizes of the drawables, so I just needed to do the same for the positions, using the scale and this new Proportion I was able to calculate using a fixed size background image

 public float convertX(float x){ 
     return x* scale * widthProportion;
 } 


 public float convertY(float y){ 
     return y* scale * heightProportion;
 } 

//calculate the positions applying the scale and the proportion
draw_x = convertX((float) (19));
draw_y = convertY((float) (279));
//draw the bitmap with the scaled position
canvas.drawBitmap(toDrawBitmap, draw_x, draw_y, null);

Long story short, to properly position the drawables I manually set the desired position in my device, calculated a scale between the densities and a porportion between the background image size and the screen size. To re-size the drawables I just used the proportion because android automatically applies the density scale.

I tested in several different phones and tablets and this approach works perfectly for phones. On tablets it gives me some minor mistakes in the re-sizing of the drawables.

Finally after all this, my question is, what is the problem with this solution? Can I make it work on every phone regardless of the size or there is a better solution for this?

Please note that this strict to Canvas. The same background is re-sized correctly for every phone if I use it in the XML layout. If I wasn't clear or I should give more information please let me know!

Community
  • 1
  • 1
caiocpricci2
  • 7,714
  • 10
  • 56
  • 88

1 Answers1

0

The first thing you have to know before solve this problem is about device phone running system. Though you suggest the phone will choose either hdpi or other versions, it depends on each phone running system.

A. Size fitting problem

The problem is how do you process the bitmap. Though you re-scale the bitmap with any math formula, the size of original bitmap will have different output for each different phone. To solve this, you have to set inScaled of bitmap to false.

B. Position fitting problem

Thus you have the problem in fitting the size of bitmap, the position of bitmap will synchronize the position depends on your phone screen size. You should define the background object and positioning the object x and y based on the background. For example if you want to put an object in the middle of phone screen no matter what phone we use it, the code must be `

canvas.drawBitmap(toDrawBitmap, background.getwidth()/2, background.getheight()/2, null);

to solve the fitting position problem.

Let me know what happen.

Marfin. F
  • 434
  • 4
  • 16