I want to make a layout similar to this one:
www.ImageBanana.net - layout.png http://www.imagebanana.com/img/9kmlhy66/thumb/layout.png
Four square buttons on the screen - each of those using half of the screen with/screen height (whichever is smaler). Independent of screen size/resolution.
I already tried to achieve this by using a LinearLayout
but the buttons are ending up using the correct width, but still having the height of the background (not square any more).
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:layout_height="wrap_content"
style="@style/CKMainButton"
android:layout_width="fill_parent"
android:text="@string/sights"
android:id="@+id/ApplicationMainSight"
android:layout_toLeftOf="@+id/ApplicationMainEvent"></Button>
<Button
android:layout_height="wrap_content"
style="@style/CKMainButton"
android:layout_width="fill_parent"
android:text="@string/sights"
android:id="@+id/ApplicationMainSight"
android:layout_toLeftOf="@+id/ApplicationMainEvent"></Button>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:layout_height="wrap_content"
style="@style/CKMainButton"
android:layout_weight="1"
android:layout_width="fill_parent"
android:text="@string/usergenerated"
android:id="@+id/ApplicationMainUserGenerated" />
<Button
android:layout_height="wrap_content"
style="@style/CKMainButton"
android:layout_weight="1"
android:layout_width="fill_parent"
android:text="@string/tours"
android:id="@+id/ApplicationMainTour"/>
</LinearLayout>
</LinearLayout>
It's looking like this: www.ImageBanana.net - layout2.png http://www.imagebanana.com/img/i2ni6g4/thumb/layout2.png
How can i acchieve the Layout to look like the image at the top above?
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
public class SquareLayout extends LinearLayout {
// Desired width-to-height ratio - 1.0 for square
private final double mScale = 1.0;
public SquareLayout(Context context) {
super(context);
}
public SquareLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (width > (int)((mScale * height) + 0.5)) {
width = (int)((mScale * height) + 0.5);
} else {
height = (int)((width / mScale) + 0.5);
}
super.onMeasure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
);
}
}
You can achieve this using ConstraintLayout. You should just add vertical guideline with the position of 50% screen width, align your buttons to the left and right side of the guideline and size them in 1:1 aspect ratio. Everything can be done in layout XML file, no additional source code required.
Once you’ve completed all of these steps, you’ll end up with something like this:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button1"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_orange_light"
android:text="1"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button2"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_blue_light"
android:text="2"
app:layout_constraintDimensionRatio="W,1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button3"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_green_dark"
android:text="3"
app:layout_constraintDimensionRatio="W,1:1"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button1" />
<Button
android:id="@+id/button4"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_purple"
android:text="4"
app:layout_constraintDimensionRatio="W,1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintTop_toBottomOf="@+id/button2" />
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
</android.support.constraint.ConstraintLayout>
Here's how this layout looks on smallest vs largest screens:
My solution is similar to the first one, however, I do the resizing in the onLayout method. Don't know which one is better.
For convenience I've wrapped my solution in a nice Android Library, see https://github.com/ronaldsteen/Android-SquareLayout-Library
I recommend the following way, it's straightforward and works
public class SquareLayout extends RelativeLayout {
public SquareLayout(Context context) {
super(context);
}
public SquareLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
}
I'm usually doing things like that:
View v; // the view i want to layout squared
v.measure(1,1);
int size = v.getMeasuredHeight(); // or v.getMeasuredWidth()...
LayoutParams params = ... // either your own, or returned from View
params.width = size;
params.height = size;
v.setLayoutParams(params);
This is certainly not the most sophisticated code, as it leaves most capabilities that can be exploited in MeasureSpec, but it gets the job done, as 'v.measure(1,1)' just says "Measure my view as it is!".
The absolute plus in my approach is that you don't have to subclass anything and you don't have to add some OnGlobalLayoutListener
to your ViewTreeObserver
. This works all at the spot where you build or inflate your layout in code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With