安卓布局:如何制作正方形按钮

12

我想制作一个类似于这个的布局:

www.ImageBanana.net - layout.png http://www.imagebanana.com/img/9kmlhy66/thumb/layout.png

屏幕上有四个正方形按钮 - 每个按钮使用屏幕宽度和屏幕高度的一半(以较小值为准)。与屏幕大小/分辨率无关。

我已经尝试使用LinearLayout来实现,但是按钮的宽度是正确的,但仍然具有背景的高度(不再是正方形)。

<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>

它看起来是这样的:www.ImageBanana.net - layout2.png http://www.imagebanana.com/img/i2ni6g4/thumb/layout2.png

我如何使布局看起来像上面的图片?

6个回答

27
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)
        );
    }
}

18
你的样本中的 mScale 是什么? - whlk
android:layout_width|height 应设置为 match_parent,姐妹布局/视图应设为 wrap_content - Gunther Piez
1
@Mannaz和其他后来查看此答案的人:mScale是您所需的宽高比,使用1表示正方形。 - comodoro
只是想说这个很好用,我已经把它加入到我的技巧库中了。 - Edward Falk
在 onMeasure 方法中,高度和宽度可能为0,因此这并不是一个完美的解决方案。 - LiangWang
0.5 代表什么意思? - ATP

7
您可以使用ConstraintLayout来实现此目的。您只需在屏幕宽度的50%位置添加垂直指南线,将按钮与指南线的左侧和右侧对齐,并以1:1的比例调整其大小。所有这些都可以在布局XML文件中完成,无需额外的源代码。
完成所有这些步骤后,您将得到类似于以下内容的东西:
<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>

以下是在最小和最大屏幕上呈现此布局的方式:

结果视图


5

1
你应该在onMeasure()方法中计算最终的大小。如果框架不喜欢你选择的大小,它会再次调用onMeasure()方法,并将测量规范设置为EXACTLY。 - Edward Falk

4
我建议采用以下方式,它很简单并且有效。
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);
   }

}

1
这种最简单的解决方案是否存在任何情况, 需要更复杂的解决方案,例如被接受的答案或 SquareFrameLayout 的 Android 实现? - TechAurelian

2

我通常做这样的事情:

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);

这段代码并不是最复杂的,因为它留下了大多数可以在MeasureSpec中利用的功能,但是它完成了工作,因为'v.measure(1,1)'只是说“按原样测量我的视图!”。
我这种方法的绝对优势在于您不必子类化任何内容,也不必将某些OnGlobalLayoutListener添加到ViewTreeObserver中。这一切都可以在您构建或膨胀代码中的布局时完成。

-1

好的,这是一个修订后的示例:

<?xml version="1.0" encoding="utf-8"?>
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="fill_parent" android:layout_width="fill_parent">
    <RelativeLayout android:id="@+id/magaLoginLayout"
        android:layout_height="fill_parent" android:layout_width="fill_parent">
        <Button android:text="@+id/Button01" android:id="@+id/Button01"
            android:layout_width="160dip" android:layout_height="160dip" android:layout_marginTop="20dip"></Button>
        <Button android:text="@+id/Button03" android:layout_below="@+id/Button01" android:id="@+id/Button03"
            android:layout_alignLeft="@+id/Button01" android:layout_height="160dip" android:layout_width="160dip"></Button>
        <Button android:text="@+id/Button04" android:layout_below="@+id/Button01" android:id="@+id/Button04"
            android:layout_toRightOf="@+id/Button03" android:layout_height="160dip" android:layout_width="160dip"></Button>
        <Button android:text="@+id/Button02" android:id="@+id/Button02" android:layout_width="wrap_content"
            android:layout_toRightOf="@+id/Button01" android:layout_alignTop="@+id/Button01" android:layout_alignParentRight="true" android:layout_height="160dip"></Button>


</RelativeLayout>

</ViewFlipper>

alt text


1
我觉得你误解了我的意思 - 我的目标不是对齐(这已经可以工作了),而是缩放按钮。我希望每一行的两个按钮都能与屏幕一样宽,所以你的答案不正确。抱歉。 - whlk
4
抱歉,但将宽度设置为绝对大小对我没有用 - 它必须是屏幕大小/方向无关的。 - whlk
2
160dip 的硬编码大小是一个错误,因为存在一些像 Galaxy Note 这样的设备。 - s_id

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接