0

I am writing a small game and I want the game canvas to keep its proportions and always be in landscape orientation. So I have a code like this:

activity_game.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:background="#Ff0000" <!-- red -->
    tools:context=".EngineActivity">

    <com.example.arsen.pw3.game.GameLayout
        android:id="@+id/mainWrapper"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#00Ff00" <!-- green -->
        android:gravity="center">

        <!-- canvas and all additional stuff comes here -->

    </com.example.arsen.pw3.game.GameLayout>

</RelativeLayout>

GameLayout.java:

public class GameLayout extends RelativeLayout {
    public GameLayout(Context context) {
        super(context);
    }

    public GameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public GameLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    // overriding onSizeChanged to take care that the proportions will be kept.
    @Override
    public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        double ratio;
        double canvasRatio = width / (double) height;
        GameSettings.DisplaySize displaySize = GameSettings.getInstance().displaySize;
        double gameDisplayRatio = displaySize.height / displaySize.width;

        if(canvasRatio > gameDisplayRatio) {
            ratio = width / displaySize.width;
        } else {
            ratio = height / displaySize.height;
        }
        getLayoutParams().height = (int) (ratio * displaySize.height);
        getLayoutParams().width = (int) (ratio * displaySize.width);
    }
}

It works properly until I return to application after switching to other.

This is how it looks when I run the app, but once I open the system switcher and then return to it, it looks like this.

So it looks that the width and height I get in onSizeChanged() method is the one from before the landscape orientation is set, and for some reason the method is not called again with the right width once the orientation is changed.

What am I doing wrong here?

Arsen
  • 664
  • 1
  • 11
  • 29

2 Answers2

0

According to the following link: Views inside a custom ViewGroup not rendering after a size change

You will need to had the following code at the end of your onSizeChanged to force a call to requestLayout()

Handler handler = new Handler();
handler.post(new Runnable() {

@Override
public void run() {
    requestLayout();
}
});      
Community
  • 1
  • 1
Kalenda
  • 1,847
  • 14
  • 15
  • Thanks for Your answer. I'm familiar with activity lifecycle. I read the article once again, but I still don't know how can I use it to solve the problem. I understand that it's caused by rotation happening in moment of pausing application, but still I don't understand, why onSizeChanged is not called when the screen is rotated back at resuming the application (or it is, but before the screen actually gets rotated), neither I don't know how to force android to call it. – Arsen Nov 06 '14 at 11:38
  • I checked it, and actually the second option is correct. onSizeChanged() is called shortly after onResume, with size from before rotation (and never again, unless I force device rotation, or lock and unlock screen). Still not having any idea how to deal with this. – Arsen Nov 06 '14 at 12:14
  • Sorry I didin't answer for so long. Unfortunately it's not helping. But as I expected. The problem here is not with Views inside a custom ViewGroup it's with a size of custom layout itself. But I found a workaround here. I'll add it as an answer, because comments are too short for it. – Arsen Nov 10 '14 at 12:21
0

As I mentioned in a comment to moise's answer, I found a workaround here. I added this code at the begining of the OnSizeChanged (right after calling super.onSizeChanged):

if(width < oldWidth) {
    width = oldWidth;
    height = oldHeight;
}

The point here was so that the layout will never get smaller, so when it initializes with right size it will stay this way forever. It wasn't a problem for me, that this would cause it to look bad in portrait orientation, because the app was supposed to work only in landscape mode. But now when I force portrait orientation, despite the expectations, it scales correctly (and then scales correctly after switching back to landscape).

So honestly, I have no idea what is happening, but this piece of code solved my problem...

I'll come back to this problem later and try to find a better solution, or at least a logical explanation for this one, but not now...

Arsen
  • 664
  • 1
  • 11
  • 29