如何在程序添加时为GridLayout子项设置layout_columnWeight?

9

我想使用GridLayout(而不是GridView)作为棋类游戏(如国际象棋或跳棋)的棋盘。由于我有点不太愿意使用64个子View的xml文件,因此我尝试了以编程方式添加它们。

为了保持简单,我开始使用TextView作为GridLayout的子View

我的问题在于View没有均匀分配,并且我不知道如何在Java代码中实现均匀分布。没有像“setWeight()”这样的方法可以设置layout_columnWeightlayout_rowWeight

目前,这是我的activity_dynamic_grid_layout.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

<ImageView
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:id="@+id/ivLogo"
    android:background="#ff0000"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"/>

<android.support.v7.widget.GridLayout
    android:id="@+id/grid_layout"
    android:background="#004080"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/ivLogo"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_marginTop="36dp">

</android.support.v7.widget.GridLayout>

我已将GridLayout的宽度和高度设置为match_parent,但我正在使用ViewTreeObserver.OnPreDrawListener在运行时更改它们,以获得一个正方形棋盘。这个方法可行,有色背景显示了预期的正方形空间。
我的onCreate()函数:
@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_dynamic_grid_layout);

    GridLayout gl = (GridLayout) findViewById(R.id.grid_layout);
    gl.setColumnCount(8);
    gl.setRowCount(8);

    for(int i=0; i<gl.getRowCount(); i++)
    {
        GridLayout.Spec rowSpec = GridLayout.spec(i, 1, GridLayout.FILL);

        for(int j=0;j<gl.getColumnCount();j++)
        {
            GridLayout.Spec colSpec = GridLayout.spec(j,1, GridLayout.FILL);

            TextView tvChild = new TextView(this);
            tvChild.setText("[ " + i + " | " + j + " ]");
            tvChild.setTextSize(18f);
            tvChild.setTextColor(Color.WHITE);
            tvChild.setGravity(Gravity.CENTER);

            GridLayout.LayoutParams myGLP = new GridLayout.LayoutParams();
            myGLP.rowSpec = rowSpec;
            myGLP.columnSpec = colSpec;

            gl.addView(tvChild, myGLP );
        }
    }

    final View rootView = findViewById(R.id.dynamic_root);

    rootView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
    {
        @Override
        public boolean onPreDraw()
        {
            int w = rootView.getMeasuredWidth();
            int h = rootView.getMeasuredHeight();
            int min = Math.min(w, h);

            ViewGroup.LayoutParams lp = gl.getLayoutParams();
            lp.width = min - min % 9;
            lp.height = lp.width;
            gl.setLayoutParams(lp);

            rootView.getViewTreeObserver().removeOnPreDrawListener(this);

            return true;
        }
    });
}

我已经尝试过的:

我在布局文件中放置了一个TextView子元素,并尝试从其GridLayout.LayoutParams中复制layout_columnWeightlayout_rowWeight:

 <android.support.v7.widget.GridLayout
 ...>   
    <TextView
        android:id="@+id/clone_my_params"
        android:text="[ 0 | 0 ]"
        android:textColor="#ffffff"
        android:textSize="18sp"
        app:layout_column="0"
        app:layout_row="0"
        app:layout_columnWeight="1"
        app:layout_rowWeight="1"
    />
</android.support.v7.widget.GridLayout>

在双重循环之前,onCreate()中需要添加额外的代码:
TextView v = (TextView)gl.findViewById(R.id.clone_my_params);
v.setGravity(Gravity.CENTER);
GridLayout.LayoutParams gridLayoutParamsToCopy = new GridLayout.LayoutParams(v.getLayoutParams());

在循环中,我跳过了(i,j) = (0,0)并进行了更改。

 GridLayout.LayoutParams myGLP = new GridLayout.LayoutParams();

to

 GridLayout.LayoutParams myGLP = new GridLayout.LayoutParams(gridLayoutParamsToCopy);

变更之前,所有元素都在左上角,多余的空间给了最后一行/列。变更之后,第一行/列有多余的空间,其他元素没有变化。

在双重循环之后调用gl.invalidate()和/或gl.requestLayout()没有效果。

因此,看来我没有通过使用复制构造函数成功设置所需的权重。


首先,如果你只需要一个8x8的正方形网格,那么制作一个自定义ViewGroup可能会更容易(而且更有效率)。其次,你应该使用一个接收浮点数的spec方法,例如http://developer.android.com/reference/android/widget/GridLayout.html#spec(int, int, android.widget.GridLayout.Alignment, float)中的Spec方法。 - user
@Luksprog - 关于自定义ViewGroup:我有一个带有自定义View的游戏原型,覆盖了“onDraw()”,现在我也在尝试使用GridView和GridLayout。我对Android开发还比较新,正在尝试从性能角度确定哪个版本最好。 关于方法:好的,如果您将API级别设置为14,则会发生这种情况-我使用了spec(int start, int size),现在才注意到有一个spec(int start, float weight)。我认为我的支持GridLayout也有它,也许这就是我缺少的东西。谢谢提示! - Bö macht Blau
@Luksprog - 任务完成 :) 在spec()的最后一个参数中添加“1f”就解决了问题。你想把它写成答案吗,这样我就可以点赞了? - Bö macht Blau
2个回答

6
-这是您需要的!:>
Button button = new Button(this);
GridLayout.LayoutParams param= new GridLayout.LayoutParams(GridLayout.spec(
            GridLayout.UNDEFINED,GridLayout.FILL,1f),
            GridLayout.spec(GridLayout.UNDEFINED,GridLayout.FILL,1f));
param.height = 0;                                                                                                           
param.width  = 0;
button.setLayoutParams(param);

1
请解释一下(编辑您的答案),您的代码是如何解决问题的。可能从代码本身并不清楚。 - CJ Dennis
已经在三个不同的模拟器上进行了测试(Android 5到7,手机和平板电脑,hdpi和mdpi):它可以正常工作,所以谢谢 :) - Bö macht Blau

1

要设置GridLayout的子元素权重,请使用spec()方法之一(例如one),该方法接受一个浮点值。

另一种方法是创建自定义视图(在这种情况下,您需要手动绘制元素)或自定义ViewGroup(在这种情况下,自定义ViewGroup将仅负责元素的定位,如果您计划拥有比简单的TextView更复杂的视图层次结构,则这将是适当的)。


再次感谢,只有一个问题:如果我要扩展ImageButton用于游戏棋子,并想利用View和ViewGroup动画,那么我应该使用GridView还是GridLayout? - Bö macht Blau
1
@0X0nosugar 没关系。从ImageButton扩展或使用任何ViewGroup都不会直接或通过布局转换更改动画视图的选项。您应该仅使用GridLayout,因为GridView更适用于其他情况。 - user

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