How to create two views in Android that use 50% height each, unless one is smaller?
Asked Answered
B

7

20

Imagine a full Android device screen, I want it split in to two sections:

  1. The upper half has text in it, which may be larger than the space available (or not) and so the text will scroll (i.e. TextView inside a ScrollView)
  2. The lower half contains a MapView control.

Looking specifically at some scenarios:

  1. If the text is small, I want the map to take up more space, i.e. more than 50%. So perhaps 20% text, 80% map.
  2. If the text is larger, it only takes up a MAXIMUM of 50% of the screen space, and then scrolls. So 50% map, 50% text.

At the moment I've assigned weights to the two parts, and that isn't too bad, but if the text is small, the map doesn't expand to take the space, and the layout has a wasted gap that the map could usefully use.

I've tried loads of combinations but can't see how to make this happen. It seems to be a common experience for me that I know what I want, but can't see how to get the available views to deliver it. I'm hoping there's a nice easy way to do this.

Please feel free to make me look like a fool and point out the obvious attribute I've missed :-)

======================================================================

As far as I can see there's no way to do this just in declarative XML and it needs doing in the code. I set the text section height to wrap_content, weight to 0 (no resizing), and have the map set to weight=1 (i.e. take up the remaining space). I then check if the text section (in a ScrollView) is taking up too much space and if so, shrink it back. This code would need changing to support a different layout orientation.

private void fixLayoutProportions()
{
    float maxPercentageOfScreenForText = 50/100;
    LinearLayout container = (LinearLayout)findViewById(R.id.container);
    ScrollView eventText = (ScrollView)findViewById(R.id.text_scroller);
    int heightAvailable = container.getHeight();
    int scrollerHeight = eventText.getHeight();
    if ( scrollerHeight>(heightAvailable*maxPercentageOfScreenForText) )      // Text section using too much space
    {
        eventText.getLayoutParams().height = (int)(heightAvailable*maxPercentageOfScreenForText) ;
        eventText.invalidate();
    }
}
Bucksaw answered 30/11, 2010 at 15:24 Comment(1)
I tried doing this as well and eventually gave up doing it in a really smart way, my solution was setting the upper scrollview max height using dips at half the screen, by using dips it adjusts it as best a posible. Of course, you need one layout for portrait and one for landscape. I left this as a comment as it really isnt all that good of a solution.Wriest
S
3

Did you try to measure your screen hight at run time:

Display display = ((WindowManager) 
      getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 
int width = display.getHeight();

Then, set your top view max_height to width*0.5 and min_height to width*0.2. Your top view has to be control (like TextView) that has min_height and max_height properties. Also, set layout_weight to 0 or leave it empty. On your bottom view set layout weight to 1.

Stich answered 30/11, 2010 at 16:5 Comment(5)
I suspect I'm gonna need to do this, but it would be easier if the layout views provided a way for the app to do it declaratively.Bucksaw
This is not very elegant. There are much better ways to do it (like using the layout_weight).Thrombophlebitis
@Thrombophlebitis I can't see any way to do this without having the code set the height of the two sections. Android View weight works great to set a relative size, but my criteria just don't seem to be covered.Bucksaw
I've selected this as the "answer" for this question as your suggestion is the closest to what I've ended up doing.Bucksaw
Just as a note: For those looking here, the solution Ollie C used is in his Question. Based on this.Blowzed
C
11

You can do it by putting everything into LinearLayout and changing following parameters:

Cupidity answered 30/11, 2010 at 16:48 Comment(3)
How? Can you give an example? I don't see how setting a sum weight on the LinearLayout would help? What would I set the child weights to for them to balance in the way I need?Bucksaw
Set the sum of weights for example to "4". You can do it in xml file. ( android:weightSum="4" ). If you want to have 50% - 50%, views should have android:layout_weight="2". If you wan to have 75% - 25%, views should have android:layout_weight="3" and android:layout_weight="1". By code you can do: ((LinearLayout.LayoutParams)child.getLayoutParams()).weight = 2.0f; parent.requestLayout();Stood
This doesn't work, as it doesn't cater to the situation where the text is very small, the map still then only takes up the specified percentage. e.g. if text set to use 50% and map 50%, then if the text actually only needs 20%, the map doesn't expand to use the space.Bucksaw
S
3

Did you try to measure your screen hight at run time:

Display display = ((WindowManager) 
      getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 
int width = display.getHeight();

Then, set your top view max_height to width*0.5 and min_height to width*0.2. Your top view has to be control (like TextView) that has min_height and max_height properties. Also, set layout_weight to 0 or leave it empty. On your bottom view set layout weight to 1.

Stich answered 30/11, 2010 at 16:5 Comment(5)
I suspect I'm gonna need to do this, but it would be easier if the layout views provided a way for the app to do it declaratively.Bucksaw
This is not very elegant. There are much better ways to do it (like using the layout_weight).Thrombophlebitis
@Thrombophlebitis I can't see any way to do this without having the code set the height of the two sections. Android View weight works great to set a relative size, but my criteria just don't seem to be covered.Bucksaw
I've selected this as the "answer" for this question as your suggestion is the closest to what I've ended up doing.Bucksaw
Just as a note: For those looking here, the solution Ollie C used is in his Question. Based on this.Blowzed
C
2

The easiest way to do 50/50 is in XML is using LinearLayout weights. Basically put the two views into a single LinearLayout set the android:layout_weight on both child views to the same value, like setting both to .5, 1, or 42. You then set the layout_width to 0px or fill_parent/match_parent.

The smaller part gets more complicated. Luckily, you can turn off weighing in Java. One way is to wait until the windows get drawn (if they are pre-populated) and measure them. This can be done on I think it was called onWindowFocusChanged

Cadence answered 19/9, 2012 at 15:42 Comment(0)
F
0

I haven't tested this, but I'd try setting your ScrollView to have android:layout_weight="1" and your MapView to have android:layout_weight="0" and a android:minHeight="240dp". The hope is that minHeight will have precedence over layout_weight.

Futility answered 30/11, 2010 at 15:35 Comment(2)
I'm not sure why you're suggesting 240dp? The app needs to work on all screen-sizes, so to force a static size I'd need to use code to dig out the screen height and calculate it, which I'd like to avoid if poss.Bucksaw
Because %age of parent isn't supported as a unit of measurement. Yes you'd have to set this in code.Futility
P
0

OK as I see its something like u are reserving at max half of ur screen to the TextView and if its more it has to scroll. I have a solution but for that you will have to fix the max no.l of lines for TextView, calculating which can be a pain :P but have a solution never the less.

main.xml file

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:scrollbars="vertical"
    android:maxLines="5"
    android:id="@+id/tv1"
    android:text="wsdvsv sjdgv jsdvn ksdjbn skjdb ksdnbk snbk snbjksn fkbj sfkbjn dfkjbndkjfbn kdjfnb kjdfnbkjdnfbk ndf bjkndf bndfjbn dfkbn jdfnbjdfnbjdfn bjdf nbkjdnf bkjdfnb kjdnfbkjdfn bkjndfbjndfjbndkjfbn dkfjbn kdjfnb kjdfnbkjdfnbjkd nfkjbndf"
    />
 <TextView 
    android:layout_width="fill_parent" 
    android:layout_below="@id/tv1"
    android:layout_height="wrap_content" 
    android:scrollbars="vertical"
    android:maxLines="5"
    android:text="Does it work ???"
    />
</RelativeLayout>

Java file:

package com.android;

import android.app.Activity;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.widget.TextView;

public class TestActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = (TextView) findViewById(R.id.tv1);
        tv.setMovementMethod(new ScrollingMovementMethod());
    }
}

If the text is say only in 2 lines "Does it work?" will shift up automatically. But the only problem i see here is the max lines to 5 is you can an max value for u i guess this might work well :)

BR, J

P.S. I haven't answered many questions before so i m not sure how to attach files :(

Propman answered 3/1, 2011 at 17:34 Comment(2)
Strange i cant see the main.xml file correctly in this however if i edit the post its visible correctly. So in case of confusion just use the above text view with a scroll and add any view below itPropman
You need to highlight code and press CTRL+K to format it properly. Use the preview next time.Thrombophlebitis
G
0

i think you have to set mapviews height as fill parent and set textviews height as wrap contetn and than for scrolling you have toset vertical scrool true for text view and as you nedded not more than 50% space textview you can set maxheight property of textview.

Gabriella answered 10/1, 2011 at 11:36 Comment(0)
P
0

I am sorry if you find this trivial. But I am suggesting it in case it did not strike you. How about using relative layout and keeping the textview always on top of the map. Make the gravity of the textview top, its width match_parent, its height wrap_content and its weight 1(same as that of thee map). That way your textview will change according to the size of the text, while not going above 50% because of the weight. As for the map, the user can pull the map down to see the hidden part under textview. It'll be as if there is no map under the textview(you know, unless you want to make the textview background transparent which i think would look cool :) ). I do not know about the map view. But I am assuming it'll be something like google maps on iphone, like you can vary size using multi-touch and scroll using single.

Passel answered 12/1, 2011 at 16:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.