Thursday, January 13, 2011

Android screen size problem

When I started working on the Learn Cards application, one of the major problems I’d bumped into, was trying to get the exact window size of my layout.
The problem is that each Android method I tried returns the phone physical resolution (480-800 on my HTC Desire), but this 800 pix height also includes the android icons bar (the one with the clock and the battery icon) and the program tile bar (in my case a plain Learn Cards text).
When I presented a grid of images (2*3) and set their size so they fill the screen (height/3 and width/2), they exceeded the screen limits (for obvious reasons: wrong height calculation).
The only useful advice I found on the net was to override the onMeasure method (stackoverflow post), but it was tricky to implement in my project, as I don't have any custom views. I tried to create my own Layout, then override the onMeasure method and create the grid there and it actually worked on my Desire. However, when I tested this solution on HTC Wildfire, it calculated the size correctly, but didn't draw the grid (I still haven’t figured why).
The solution that worked for me was to calculate the height once at the application start via overriding the linerlayout, and then using this value in the rest of my project.
Here is a small example that implements the solution described above: (Sample code available for download Here )




First we need to create our LayoutMessure, which overrides the LinearLayout class:






        public class LayoutMessure extends LinearLayout




Then override the onMeasure method and save the needed values values for a future use:






        static public int windowW=0;
static public int windowH=0 ;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
{
// we overriding onMeasure because this is where the application gets its right size.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
windowW = getMeasuredWidth();
windowH = getMeasuredHeight();
}






Now we need to add our new custom LayoutMessure to our main screen:
Add this code right after the first layout:






        <view
         class="il.yavji.screensize.LayoutMessure"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:id="@+id/customlayout"
         android:gravity="center"
        >




And close it right before you close the first (main) layout:



        </view>


Now each time the main screen is created, our custom class will measure the screen size and you will be able to get it later through LayoutMessure.windowW and LayoutMessure.windowH properties.




One last thing - this solution will work for all application screens except the first one, because the onMessure called only after  onCreate finished.
If you intend to use it on main screen too, just add another dummy screen that does nothing except for calling the main screen, and add the view to it. 

6 comments:

  1. Very nice tutorial! Thx!

    ReplyDelete
  2. Thank you very much, good job.

    ReplyDelete
  3. hi there

    could you plese explain what you mean by "just add another dummy screen that does nothing except for calling the main screen, and add the view to it"

    thanx heaps

    ReplyDelete
  4. By dummy screen i meant a splash screen, or even empty screen that calls startActivity in on create.
    So we wont see the screen but it still would work.
    You can see it in the source code.

    ReplyDelete
  5. I have implemented your solution but there is a big problem. The onMeasure function is called several times by the framework. The first call sets the desired width/height values, but the later calls sets the full height of the screen. So I am in the same situation than before.
    Do you have any idea how to solve this?

    ReplyDelete
    Replies
    1. Can't you just catch the first one and then only update windowW and windowH if they are not equal to the default value of 0.

      Delete