Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fullscreen App, Layout shifted down by height of notification bar

Tags:

android

I have an App that has a toolbar at the bottom of the screen and the rest is filled with a custom View (see xml below). Now when I make the App full screen (I tried all possibilities, programmatically and via Manifest.xml), when it's started the whole layout seems to be shifted down by about the height of the notification bar. The buttons in the toolbar are only visible half-way. Sometimes, all of it moves up after a few seconds, or when I click a button in the toolbar.

enter image description here

I'm pretty sure, that it's a problem with my custom view, because I do not get this effect if I replace it with a Button or the like. I guess it must have something to do with the onMeasure method. I don't really know how to implement it, my version is shown below. The custom view is used for drawing inside, so basically it wants to be as large as possible.

Any help would be much appreciated. I searched for several hours already, but no clue yet.

layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:orientation="vertical">
    <com.example.MyCanvasView 
        android:id="@+id/canvas" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:layout_weight="1" 
         />
    <!-- Buttonbar -->
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingTop="4dp"
        android:orientation="horizontal"
        android:background="@android:drawable/bottom_bar"
        >
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="1"
        />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="2"
        />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="3"
        />
    </LinearLayout>
</LinearLayout>

And this is my onMeasure method:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    setMeasuredDimension(width, height);
}
like image 288
Ridcully Avatar asked Oct 12 '22 12:10

Ridcully


2 Answers

You're not taking the mode into account when you're setting your measurement.

The mode of a MeasureSpec can be one of MeasureSpec.EXACTLY, MeasureSpec.AT_MOST, or MeasureSpec.UNSPECIFIED. Simply accepting the size component and setting your measured size to that is appropriate for EXACTLY, but it isn't often the right thing for the others.

Because you're trying to use layout_weight in addition to a height of wrap_content on this custom view, the following is happening:

Your custom view is the first child of the LinearLayout with a height of wrap_content so LinearLayout measures it. Since LinearLayout has been told by the LayoutParams that it should wrap_content, it measures your custom view with a MeasureSpec mode of AT_MOST and a size of the entire available space.

But your custom view is greedy. It decides to take all of the space available. In essence, you have implemented your measurement to treat wrap_content as match_parent.

Now there's no more space left. The lower button bar gets measured accordingly but it's not done yet, there's a child with weight. In a LinearLayout any space left over after all normal measurement is complete is divided among the weighted children according to their weight values. This isn't the behavior you want.

When you use weight to fill available vertical space like you're doing in this layout, you normally want to set the layout_height to 0dip. This will make LinearLayout skip the first measure pass on that child and only use the weighted measurement pass to measure your view, giving it the remaining available space.

like image 141
adamp Avatar answered Oct 20 '22 16:10

adamp


I found the reason for the described behaviour. I had set the view to be focusable in touchmode via setFocusableInTouchMode(true) in the onCreate() method. As soon as I removed this, it works fine. Thanks to adamp though -- your description of what goes on during layout and measuring was very interesting.

But that leaves me with the problem that I do not receive any key/button clicks any more :-(

like image 26
Ridcully Avatar answered Oct 20 '22 15:10

Ridcully