Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have equal size of width and height [square shape] using layout_weight?

I have following code:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1" >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Test 1"
        android:textSize="24sp" />
</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1" >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Test 2"
        android:textSize="24sp" />
</LinearLayout>

that results:

enter image description here

How can I have equal size of View's height with its width (that is resulted by layout_weight)?

like image 444
Rendy Avatar asked Aug 05 '14 15:08

Rendy


3 Answers

Simpler solution is to pass the width measurement specification into the height specification when calling onMeasure (or the other way around if you want the height to determine the square size).

import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;

public class SquareLinearLayout extends LinearLayout{
    public SquareLinearLayout(Context context) {
        super(context);
    }

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
        // or super.onMeasure(heightMeasureSpec, heightMeasureSpec);
    }
}
like image 27
sixones Avatar answered Nov 04 '22 09:11

sixones


You have to override the onMeasure method set the same height as the height. Please see this question: Simple way to do dynamic but square layout

This is the complete solution that I come up with:

SquareLinearLayout.java :

public class SquareLinearLayout extends LinearLayout {
public SquareLinearLayout(Context context) {
    super(context);
}

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

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

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    int widthDesc = MeasureSpec.getMode(widthMeasureSpec);
    int heightDesc = MeasureSpec.getMode(heightMeasureSpec);
    int size = 0;
    if (widthDesc == MeasureSpec.UNSPECIFIED
            && heightDesc == MeasureSpec.UNSPECIFIED) {
        size = getContext().getResources().getDimensionPixelSize(R.dimen.default_size); // Use your own default size, for example 125dp
    } else if ((widthDesc == MeasureSpec.UNSPECIFIED || heightDesc == MeasureSpec.UNSPECIFIED)
            && !(widthDesc == MeasureSpec.UNSPECIFIED && heightDesc == MeasureSpec.UNSPECIFIED)) {
        //Only one of the dimensions has been specified so we choose the dimension that has a value (in the case of unspecified, the value assigned is 0)
        size = width > height ? width : height;
    } else {
        //In all other cases both dimensions have been specified so we choose the smaller of the two
        size = width > height ? height : width;
    }
    setMeasuredDimension(size, size);
 }
}

activity_my.xml :

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:listitem="@layout/item"
tools:context=".MyActivity">

</ListView>

item.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">

        <com.appsrise.squarelinearlayout.SquareLinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@android:color/holo_blue_bright">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="Test 1"
                android:textSize="24sp" />
        </com.appsrise.squarelinearlayout.SquareLinearLayout>

        <com.appsrise.squarelinearlayout.SquareLinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@android:color/holo_green_light">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="Test 2"
                android:textSize="24sp" />
        </com.appsrise.squarelinearlayout.SquareLinearLayout>

</LinearLayout>

MyActivity.java :

public class MyActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);

    ListView listView = (ListView) findViewById(R.id.listview);
    listView.setAdapter(new BaseAdapter() {

        private LayoutInflater mInflater = LayoutInflater.from(MyActivity.this);

        @Override
        public int getCount() {
            return 100;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null)
                convertView = mInflater.inflate(R.layout.item, parent, false);
            return convertView;
        }
    });
 }
}
like image 160
Eduard B. Avatar answered Nov 04 '22 11:11

Eduard B.


Xamarin version

[Register("SquareFrameLayout")]
public class SquareFrameLayout : LinearLayout
{
    public SquareFrameLayout(Context context) : base(context)
    {
    }

    public SquareFrameLayout(Context context, IAttributeSet attrs) : base(context, attrs)
    {
    }

    public SquareFrameLayout(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
    {
    }

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        base.OnMeasure(widthMeasureSpec, heightMeasureSpec);

        var width = MeasureSpec.GetSize(widthMeasureSpec);
        var height = MeasureSpec.GetSize(heightMeasureSpec);
        var widthDesc = MeasureSpec.GetMode(widthMeasureSpec);
        var heightDesc = MeasureSpec.GetMode(heightMeasureSpec);

        if (widthDesc == MeasureSpecMode.Unspecified && heightDesc == MeasureSpecMode.Unspecified)
        {
            //size = Context.Resources.GetDimensionPixelSize(Resource.Dimension.default_size); // Use your own default size, for example 125dp
            height = width = 0;
        }
        else if(heightDesc != MeasureSpecMode.Unspecified && widthDesc == MeasureSpecMode.Unspecified)
        {
            width = height;
        }
        else if (widthDesc != MeasureSpecMode.Unspecified && heightDesc == MeasureSpecMode.Unspecified)
        {
            height = width;
        }
        else
        {
            //In all other cases both dimensions have been specified so we choose the smaller of the two
            var size = width > height ? height : width;
            width = height = size;
        }

        SetMeasuredDimension(width, height);
    }

and

[Register("SquareLinearLayout")]
public class SquareLinearLayout : LinearLayout
{
    public SquareLinearLayout(Context context) : base(context)
    {
    }

    public SquareLinearLayout(Context context, IAttributeSet attrs) : base(context, attrs)
    {
    }

    public SquareLinearLayout(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
    {
    }

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        base.OnMeasure(widthMeasureSpec, heightMeasureSpec);

        var width = MeasureSpec.GetSize(widthMeasureSpec);
        var height = MeasureSpec.GetSize(heightMeasureSpec);
        var widthDesc = MeasureSpec.GetMode(widthMeasureSpec);
        var heightDesc = MeasureSpec.GetMode(heightMeasureSpec);

        if (widthDesc == MeasureSpecMode.Unspecified && heightDesc == MeasureSpecMode.Unspecified)
        {
            //size = Context.Resources.GetDimensionPixelSize(Resource.Dimension.default_size); // Use your own default size, for example 125dp
            height = width = 0;
        }
        else if(heightDesc != MeasureSpecMode.Unspecified && widthDesc == MeasureSpecMode.Unspecified)
        {
            width = height;
        }
        else if (widthDesc != MeasureSpecMode.Unspecified && heightDesc == MeasureSpecMode.Unspecified)
        {
            height = width;
        }
        else
        {
            //In all other cases both dimensions have been specified so we choose the smaller of the two
            var size = width > height ? height : width;
            width = height = size;
        }

        SetMeasuredDimension(width, height);
    }
}
like image 27
Softlion Avatar answered Nov 04 '22 09:11

Softlion