0

I have this scenario: A horizontal LinearLayout that fills the container and weightSum=100, and two views inside with weight of 50 each.

Now how do I make these two views square (e.g. the height must be equal to their width). The number of LinearLayout rows is unknown, so basically, I can not wrap them in a vertical container with weights in this case.

Dzhuneyt
  • 8,437
  • 14
  • 64
  • 118

1 Answers1

1

Now how do I make these two views square (e.g. the height must be equal to their width).

If you have just those two views in the LinearLayout you have two options:

  1. Don't set your layout file directly as the content view, instead inflate it so you have a reference to the root from that file. Then post a Runnable on that root view, calculate the desired height and set it back to each of the two children of the LinearLayout that wraps them:

    final View v = getLayoutInflater().inflate(
            R.layout.views_specialheight, null);
    v.post(new Runnable() {
    
        @Override
        public void run() {
            setupHeight((ViewGroup) v);
        }
    });
    setContentView(v);
    

    where setupHeight() is the method:

    private void setupHeight(ViewGroup vg) {
        int count = vg.getChildCount();
        for (int i = 0; i < count; i++) {
            final View v = vg.getChildAt(i);            
            if (v instanceof LinearLayout) {
                int width = v.getWidth();
                LinearLayout.LayoutParams lp;
                View one = ((LinearLayout) v).getChildAt(0);
                lp = (LinearLayout.LayoutParams) one.getLayoutParams();
                lp.height = width / 2;
                one.setLayoutParams(lp);
                View two = ((LinearLayout) v).getChildAt(1);
                lp = (LinearLayout.LayoutParams) two.getLayoutParams();
                lp.height = width / 2;
                two.setLayoutParams(lp);
            }
        }
    }
    

    This method will work pretty well if you just have a wrapper ViewGroup subclass that wraps those LinearLayout rows. It can(and should) be improved, but I'm sure you get the point.

  2. The second option is to use a custom ViewGroup(this may be used depending on what you were planing to do with the LinearLayout) instead of the LinearLayout like this:

    <com.luksprog.oat.views.SpecialHeightViewGroup
         android:layout_width="match_parent"
         android:layout_height="wrap_content" >
    
       <Button
           android:id="@+id/button1"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:background="#0077cc"
           android:text="Button" />
    
       <Button
           android:id="@+id/button2"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:background="#99cc00"
           android:text="Button" />
    </com.luksprog.oat.views.SpecialHeightViewGroup>
    

The SpecialHeightViewGroup is a class like this:

class SpecialHeightViewGroup extends ViewGroup {

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

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

public SpecialHeightViewGroup(Context context) {
    super(context);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    if (widthMode == MeasureSpec.EXACTLY
            || widthMode == MeasureSpec.AT_MOST) {
        measureChildren(MeasureSpec.makeMeasureSpec(widthSize / 2,
                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                widthSize / 2, MeasureSpec.EXACTLY));
        measureChildren(MeasureSpec.makeMeasureSpec(widthSize / 2,
                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                widthSize / 2, MeasureSpec.EXACTLY));
        setMeasuredDimension(widthSize, widthSize / 2);
    } else {
        widthSize = 800; // we don't have restrictions, make it as big as we want
        measureChildren(MeasureSpec.makeMeasureSpec(widthSize / 2,
                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                widthSize / 2, MeasureSpec.EXACTLY));
        measureChildren(MeasureSpec.makeMeasureSpec(widthSize / 2,
                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                widthSize / 2, MeasureSpec.EXACTLY));
        setMeasuredDimension(widthSize, 400);
    }       
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {      
    View one = getChildAt(0);
    one.layout(0, 0, getWidth() / 2, getHeight());
    View two = getChildAt(1);
    two.layout(getWidth() / 2, 0, getWidth(), getHeight());     
}

}

The custom class isn't properly tested so it may have bugs(it's just an example).

Offtopic: Are you trying by any chance to create an UI like on the new Windows phones(with the tiles thing)?

user
  • 86,916
  • 18
  • 197
  • 190
  • 1
    Yes, I am creating to recreate the Nokia Lumia UI. For example: http://i.imgur.com/Lw85o.jpg I never imagined it would be that much complex to create something as simple as a bunch of rows with squares in them in Android. – Dzhuneyt Sep 20 '12 at 15:46
  • @ColorWP.com The first method is not that complex, but in the end it all depends on how you work with those rows. You may want to look at the `GridLayout` also. – user Sep 20 '12 at 15:48