Reputation: 157
I have two custom views, which i want to layout vertically. The first view is a sort of playing board, which is a square. The square scales easily and can adapt to almost any available space.
The second view is a subclass of [TableLayout][1]
which holds several Button
s. The number of rows/columns is determined at runtime.
To ease explaining, i'll call the first view board and the second one table.
I want board to be displayed at the top of the screen and table should go right below it. Table should take the vertical space it needs (which basically depends on the number of rows). Board should set it's square edge size to the minimum of the available width and the available height, i.e. scale down.
I tried to achieve this using a [RelativeLayout][2]
like so:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/default_padding"
>
<some.package.Table
android:id="@+id/table"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/default_padding"
/>
<some.package.Board
android:id="@+id/board"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_above="@id/table"
/>
</RelativeLayout>
With this approach I had hoped that the table would be measured first and the remaining available screen height would be passed as maximum (i.e. AT_MOST
) height spec to the onMeasure
of board. This assumption appears to be wrong.
When I use this layout, the board seems to be resized to zero size, i.e. it is not rendered.
When I turn things around like so:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/default_padding"
>
<some.package.Board
android:id="@+id/board"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
<some.package.Table
android:id="@+id/table"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/default_padding"
android:layout_below="@id/board"
/>
</RelativeLayout>
The board takes up too much vertical space and the table gets cut off at the bottom
In both cases board get's the display width as AT_MOST
width spec and the display height (minus status bar and action bar height) as AT_MOST
height spec. So my onMeasure
implementation takes the minimum of both as square size which does not leave enough room for the table view.
Could anyone give me a heads up how to go about this, please? Do I maybe need to add a nested layout? Or work with layout weights? - I've refrained from doing so, as weights are for relative sizing in my understanding.
Thanks & kind regards
Edit after Gabe's answer:
After trying Gabe's suggestion I logged some data in the onMeasure
methods of board and table:
table: wM=EXACTLY minW=0 ws=736 hM=EXACTLY minH=0 hs=1006
board: wM=AT_MOST minW=0 ws=736 hM=AT_MOST minH=0 hs=1006
board: wM=EXACTLY minW=0 ws=736 hM=EXACTLY minH=0 hs=1006
table: wM=EXACTLY minW=0 ws=736 hM=AT_MOST minH=0 hs=0
I/Choreographer﹕ Skipped 206 frames! The application may be doing too much work on its main thread.
D/dalvikvm﹕ GC_FOR_ALLOC freed 305K, 8% free 4880K/5252K, paused 103ms, total 105ms
table: wM=EXACTLY minW=0 ws=736 hM=EXACTLY minH=0 hs=1006
board: wM=AT_MOST minW=0 ws=736 hM=AT_MOST minH=0 hs=1006
board: wM=EXACTLY minW=0 ws=736 hM=EXACTLY minH=0 hs=1006
table: wM=EXACTLY minW=0 ws=736 hM=AT_MOST minH=0 hs=0
wM is the width mode from the MeasureSpec
, minW is getSuggestedMinimumWidth()
, ws is the width size from the MeasureSpec
.
Same applies for hM, minH and hs.
I have not overridden onMeasure
in table (well yes, I have, but it just logs the data and calls super.onMeasure()
). The behaviour implemented in board.onMeasure()
is described above.
I'm still puzzled...
Edit after kha's answer:
kha's suggestion worked. The working XML-layout is
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/default_padding"
>
<some.package.Table
android:id="@+id/table"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/default_padding"
android:layout_alignParentBottom="true"
/>
<some.package.Board
android:id="@+id/board"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_above="@id/table"
/>
</RelativeLayout>
The logging output is now:
board: wM=AT_MOST minW=0 ws=736 hM=AT_MOST minH=0 hs=1006
table: wM=EXACTLY minW=0 ws=736 hM=EXACTLY minH=0 hs=1006
table: wM=EXACTLY minW=0 ws=736 hM=AT_MOST minH=0 hs=1006
board: wM=EXACTLY minW=0 ws=736 hM=EXACTLY minH=0 hs=702
I/Choreographer﹕ Skipped 118 frames! The application may be doing too much work on its main thread.
board: wM=AT_MOST minW=0 ws=736 hM=AT_MOST minH=0 hs=1006
table: wM=EXACTLY minW=0 ws=736 hM=EXACTLY minH=0 hs=1006
table: wM=EXACTLY minW=0 ws=736 hM=AT_MOST minH=0 hs=1006
board: wM=EXACTLY minW=0 ws=736 hM=EXACTLY minH=0 hs=702
Upvotes: 0
Views: 744
Reputation: 19993
Try this:
Move and change the
android:layout_below="@id/board"
to
android:layout_above="@id/table"
on your other layout.
Do this in conjunction with setting android:alignParentBottom=true
on your table layout.
Upvotes: 1
Reputation: 93561
The order of views in a relative layout determines the z ordering if they overlap, not the order they're drawn in. Also, weights only do things for LinearLayout, not Relative.
The second XML is almost correct- it will measure out the table, let it take as much room as it wants, then layout the board below it. Change the height of the board to match_parent and it should work- it will force it to take up no more than the remaining room.
Upvotes: 0