So far I have tried many ways of scaling images to screen sizes and none of them seem to work for me. I am still new to java and the idea of having a UI that fits to any screen size seems foreign to me. I am drawing bitmaps with the Canvas class. I have tried creating a scaledBitmap and have seen no difference. I want a simple main menu screen like this
This must be a really common issue because all apps would need to do this. I really could use some help understanding how this works. On some phones it looks alright but on others the images are either too large or off centered.
My code is below. If someone could please help me out here, this is for a school project due pretty soon :P Thanks guys!
public MainMenu(Context context) {
super(context);
titleBounds = new RectF();
playBounds = new RectF();
scoreBounds = new RectF();
soundBounds = new RectF();
creditBounds = new RectF();
titlePaint = new Paint();
playPaint = new Paint();
play = BitmapFactory.decodeResource(getResources(), R.drawable.play);
playGlow = BitmapFactory.decodeResource(getResources(), R.drawable.playglow);
sound = BitmapFactory.decodeResource(getResources(), R.drawable.sound);
soundGlow = BitmapFactory.decodeResource(getResources(), R.drawable.soundglow);
// Get window size and save it to screenWidth and screenHeight.
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screenWidth = size.x;
screenHeight = size.y;
playy = Bitmap.createScaledBitmap(play, convertToPx(screenWidth), convertToPx(screenHeight), true);
playSound(context, R.raw.loop);
}
public int convertToPx(int dp) {
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
return (int) (dp * scale + 0.5f);
}
@Override protected void onDraw(Canvas canvas) {
ViewGroup parent = (ViewGroup)getParent();
playBounds.set(screenWidth / 2 - play.getWidth() / 2, screenHeight * 1/3 - play.getHeight() / 2, playBounds.left + play.getWidth(), playBounds.top + play.getHeight());
soundBounds.set(playBounds.centerX() - sound.getWidth() / 2, playBounds.bottom + 10, soundBounds.left + sound.getWidth(), soundBounds.top + sound.getHeight());
if (playClick == false) canvas.drawBitmap(playy, null, playBounds, null);
else canvas.drawBitmap(playGlow, null, playBounds, null);
if (soundClick == false) canvas.drawBitmap(sound, null, soundBounds, null);
else canvas.drawBitmap(soundGlow, null, soundBounds, null);
Try this, on the image use scaleType="fitXY" with this it would span to the bound of the view.
The screen sizes you've gotten from wm.getDefaultDisplay().getSize() are in pixels, not in dp. So you can just use them without converting them.
Something like...
If you are trying to create a game, I would advise against using Canvas. Instead, you should use the faster GLSurfaceView. Better yet, use a cross platform game engine like Corona SDK or Unity or Cocos2dx. Development will be much easier that way, and the performance would be great too.
EDIT: What you ultimately want is a consistent scaling for all your assets without changing their aspect ratio. You need to write an helper method to figure out this ratio, then multiply this ratio to all your dimentions.
Explanation: We have
dimRatio
to figure out the final pixel value of all your bitmap assets. When you position them, you have to addxOffset
oryOffset
accordingly to correctly offset the blank region of the screen, which results from the fact that device screen's aspect ratio is different than your game's intended aspect ratio. The matrix combines all that so we don't have to use these variables every time we draw. We can just use the matrix.Draw Example:
I just wrote this without really testing it. It's just for the idea. Hope you get the idea.
EDIT2: Realized xOffset and yOffset were reversed. Fixed it.