我想有一个2x2网格内的按钮。这只是ICS,所以我试图使用新的GridLayout给定。

这是我的布局的XML:

 <?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/favorites_grid"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00ff00"
    android:rowCount="2"
    android:columnCount="2">
  <Button
      android:text="Cell 0"
      android:layout_row="0"
      android:layout_column="0"
      android:textSize="14dip" />
  <Button
      android:text="Cell 1"
      android:layout_row="0"
      android:layout_column="1"
      android:textSize="14dip" />

  <Button
      android:text="Cell 2"
      android:layout_row="1"
      android:layout_column="0"
      android:textSize="14dip" />
  <Button
      android:text="Cell 3"
      android:layout_row="1"
      android:layout_column="1"
      android:textSize="14dip" />
</GridLayout>

问题是我的视图没有为每一行均匀地拉伸。这导致GridLayout的右侧有很多额外的空间。

我尝试设置layout_gravity="fill_horizontal",但这只适用于该行的最后一个视图。这意味着单元格1会一直延伸,为单元格0提供足够的空间。

如何解决这个问题?


当前回答

关于网格布局的一些技巧。

Default Grid layout works best on min SDK 21+ . GridLayout's height/width should be either fixed or match_parent .It is because Grid layout calculates the height/width of its child, and having the variable height of its own could cause issues in calculation of the exact height. Grid layout ignores the margins on children by default, so we should be using android:useDefaultMargins="true" if we want children to control their margins. To make a dynamic, auto-stretching group of views with Grid layout, either: the parent would be controlling both: the max height of the total group and number of elements in each row or the parent would be controlling the number of columns in each row,and the children will be controlling the total height.

第一个场景的优点是我们可以在组中添加任意数量的孩子,他们都将很好地均匀伸展。缺点是我们得到的是一个固定规模的群体。而内容较大的儿童也占据了固定的空间。

第二个场景的优点是我们可以添加更多的子节点,由子节点决定组的高度。在父元素的顶部附加一个嵌套的滚动视图将使整个元素列表可滚动。 缺点是,儿童控制组的高度和变量高度,可能会导致整个视图看起来混乱。

如果我们稍微调整一下,这两种情况都可以发挥它们的优点,它们的缺点可以被最小化。

第一个场景的例子:

    <GridLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:columnCount="2"
        android:useDefaultMargins="true">

        <View
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_rowWeight="1"
            android:layout_columnSpan="1"
            android:layout_columnWeight="1"
            android:layout_gravity="fill"
            android:layout_marginHorizontal="8dp"
            android:layout_marginVertical="8dp"
            android:background="@color/black" />

        <View
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_rowWeight="1"
            android:layout_columnSpan="1"
            android:layout_columnWeight="1"
            android:layout_gravity="fill"

            android:layout_marginHorizontal="8dp"
            android:layout_marginVertical="8dp"
            android:background="@color/black" />

        <View
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_rowWeight="1"
            android:layout_columnSpan="2"
            android:layout_columnWeight="1"
            android:layout_gravity="fill"

            android:layout_marginHorizontal="8dp"
            android:layout_marginVertical="8dp"
            android:background="@color/black" />

        <View
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_rowWeight="1"
            android:layout_columnSpan="1"
            android:layout_columnWeight="1"
            android:layout_gravity="fill"
            android:layout_marginHorizontal="8dp"
            android:layout_marginVertical="8dp"
            android:background="@color/black" />

        <View
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_rowWeight="1"
            android:layout_columnSpan="1"
            android:layout_columnWeight="1"
            android:layout_gravity="fill"

            android:layout_marginHorizontal="8dp"
            android:layout_marginVertical="8dp"
            android:background="@color/black" />

        <View
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_rowWeight="1"
            android:layout_columnSpan="2"
            android:layout_columnWeight="1"
            android:layout_gravity="fill"

            android:layout_marginHorizontal="8dp"
            android:layout_marginVertical="8dp"
            android:background="@color/black" />

     
        <!--        
        add more elements here with same attributes and they will fit on their own!
        -->

    </GridLayout>

输出:

第二个场景:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:ignore="HardcodedText"
    >

    <GridLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:columnCount="2"
        android:orientation="horizontal"
        android:useDefaultMargins="true"
        >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_columnSpan="1"
            android:text="this is a text"
            android:textColor="@color/white"
            android:layout_gravity="center"
            android:layout_margin="8dp"
            android:background="@color/black"
            />
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnSpan="1"
            android:layout_gravity="fill_horizontal"
            android:text="this is something cool. this should be taking more space but it is also controlling the total height of row"
            android:textColor="@color/white"
            android:gravity="center"
            android:layout_margin="8dp"
            android:background="@color/black"
            />
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnSpan="1"
            android:layout_gravity="fill_horizontal"
            android:text="once the width is determined by any child, the whole column shall take the same height"
            android:textColor="@color/white"
            android:gravity="center"
            android:layout_margin="8dp"
            android:background="@color/black"
            />
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnSpan="1"
            android:layout_gravity="fill"
            android:text="this column can only control how they shall look by layout gravity. this should look like column 0,0 but its  taking full row height/width"
            android:textColor="@color/white"
            android:gravity="center"
            android:layout_margin="8dp"
            android:background="@color/black"
            />

        <!--

        -->



    </GridLayout>

</FrameLayout>

outpus:

其他回答

我能找到的最好的解决方案是为你想要的每一行使用线性布局(水平),并在其中分配按钮(单元格)宽度为0dp,权重为1。对于每个线性布局(行),将高度分配为0dp,权重分配为1。 找到下面的代码-也是android:layout_gravity="center_vertical"用于在一行中对齐按钮,以防它们包含可变长度的文本。 使用0dp和权重是一个非常简洁但不太为人所知的技巧。

<LinearLayout
 android:id="@+id/parent_layout"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="@drawable/button_bue_3d"
 android:orientation="vertical" >

            <LinearLayout
                android:id="@+id/layout_row1"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"

                android:orientation="horizontal" >

                <Button
                    android:id="@+id/button1"
                    style="?android:attr/buttonStyleSmall"
                   android:layout_height="wrap_content"
                   android:layout_width="0dp"
                   android:layout_weight="1"
                    android:clickable="false"
                   android:layout_gravity="center_vertical"
                    android:text="ssssssssssssssssssssssssss" />

                <Button
                    android:id="@+id/button2"
                    style="?android:attr/buttonStyleSmall"
                    android:clickable="false"
                    android:layout_height="wrap_content"
                     android:layout_width="0dp"
                   android:layout_weight="1"
                   android:layout_gravity="center_vertical"
                    android:text="sggggggg" />


            </LinearLayout>

            <LinearLayout
                android:id="@+id/layout_row2"
                android:layout_weight="1"
                android:layout_width="match_parent"
                  android:layout_height="0dp"

                android:orientation="horizontal" >

                <Button
                    android:id="@+id/button3"
                    style="?android:attr/buttonStyleSmall"
                    android:layout_height="wrap_content"
                     android:layout_width="0dp"
                   android:layout_weight="1"
                    android:layout_gravity="center_vertical"
                    android:text="s" />

                <Button
                    android:id="@+id/button4"
                    style="?android:attr/buttonStyleSmall"
                    android:layout_height="wrap_content"
                     android:layout_width="0dp"
                   android:layout_weight="1"
                    android:clickable="false"
                     android:layout_gravity="center_vertical"
                    android:text="s" />


            </LinearLayout>


       </LinearLayout>

在我的例子中,我是动态添加按钮,所以我的解决方案需要一些XML部分和一些Java部分。我必须从几个不同的地方找到并混合解决方案,我想我将在这里分享,以便其他人寻找类似的解决方案可能会发现它有帮助。

我的布局文件XML的第一部分…

<android.support.v7.widget.GridLayout
    xmlns:grid="http://schemas.android.com/apk/res-auto"
    android:id="@+id/gl_Options"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    grid:useDefaultMargins="true">
</android.support.v7.widget.GridLayout>

grid: usedefaultmargin ="true"不是必需的,但我添加了,因为这对我来说更好,你可以应用其他视觉影响(例如填充),如在这里的一些答案中提到的。现在对于按钮,因为我必须动态添加它们。这是我的代码的Java部分,使这些按钮,我只包括那些与此上下文相关的行。假设我必须使按钮从许多myOptions可用到我的代码,我没有复制OnClickListener代码以及。

import android.support.v7.widget.GridLayout;   //Reference to Library

public class myFragment extends Fragment{
    GridLayout gl_Options;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        gl_AmountOptions = (GridLayout)view.findViewById( R.id.gl_AmountOptions );
        ...
        gl_Options.removeAllViews();     // Remove all existing views
        gl_AmountOptions.setColumnCount( myOptions.length <= 9 ? 3: 4 );  // Set appropriate number of columns

        for( String opt : myOptions ) {
            GridLayout.LayoutParams lParams   = new GridLayout.LayoutParams( GridLayout.spec( GridLayout.UNDEFINED, 1f), GridLayout.spec( GridLayout.UNDEFINED, 1f));
            // The above defines LayoutParameters as not specified Column and Row with grid:layout_columnWeight="1" and grid:layout_rowWeight="1"
            lParams.width = 0;    // Setting width to "0dp" so weight is applied instead

            Button b = new Button(this.getContext());
            b.setText( opt );
            b.setLayoutParams(lParams);
            b.setOnClickListener( myClickListener );
            gl_Options.addView( b );
        }
    }
}

因为我们从支持库中使用GridLayout而不是标准的GridLayout,我们必须在YourProject中告诉它的等级。级文件。

dependencies {
    compile 'com.android.support:appcompat-v7:23.4.0'
    ...
    compile 'com.android.support:gridlayout-v7:23.4.0'
}

main。xml

<GridLayout
    android:id="@+id/grid_related_news"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp"
    android:padding="3dp"
    android:columnCount="2">

</GridLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="0dp"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_columnWeight="1"
    android:gravity="center"
    android:padding="3dp"
    android:layout_gravity="fill_horizontal"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        app:cardBackgroundColor="@color/white"
        app:cardCornerRadius="5dp"
        app:cardElevation="2dp"
        android:layout_margin="4dp">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/img_related_news"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layoutDirection="rtl"
                android:scaleType="centerCrop"
                app:layout_constraintDimensionRatio="H,1:1"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@drawable/light_gray" />

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:background="#59000000"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/txt_related_news_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="12dp"
                android:layout_marginTop="6dp"
                android:layout_marginEnd="12dp"
                android:layout_marginBottom="12dp"
                android:elevation="2dp"
                android:fontFamily="@font/yekan_bold"
                android:letterSpacing="-0.1"
                android:lineSpacingExtra="4dp"
                android:maxLines="4"
                android:textColor="@color/white"
                android:textSize="13sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                tools:text="@string/lorem_ipsum_sentence" />

        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.cardview.widget.CardView>

</LinearLayout>

java

GridLayout grid_related_news = findViewById(R.id.grid_related_news);
View view = LayoutInflater.from(this).inflate(R.layout.related_item, (ViewGroup) grid_related_news, false);
ImageView img_related_news = view.findViewById(R.id.img_related_news);
...

grid_related_news.addView(view);

你可以用这个例子

你可以动态设置每个子节点的宽度:

GridLayout.LayoutParams params = (GridLayout.LayoutParams) child.getLayoutParams();
    params.width = (parent.getWidth()/parent.getColumnCount()) -params.rightMargin - params.leftMargin;
    child.setLayoutParams(params);

更新:API 21支持权重。详见保罗的回答。

使用GridLayout时有一些限制,下面的引用摘自文档。

GridLayout不支持权重原则,因为 以权重定义。一般来说,因此不可能 配置GridLayout将多余的空间分布在非平凡中 多行或多列之间的比例…为了完全控制 超过多余的空间分布在行或列;使用线性布局 子视图来保存关联单元格组中的组件。

下面是一个使用LinearLayout子视图的小例子。(我使用空间视图占用未使用的区域,并将按钮推到所需的位置。)

<GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:columnCount="1"
>
    <TextView
        android:text="2x2 button grid"
        android:textSize="32dip"
        android:layout_gravity="center_horizontal" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" android:orientation="horizontal">
        <Space
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button 1" />
        <Space
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="start"
            android:text="Button 2" />
        <Space
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
    >
        <Space
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button 3" />
        <Space
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="start"
            android:text="Button 4" />
        <Space
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    </LinearLayout>
</GridLayout>