使用 GridView 居中方形棋盘
Centered square chessboard using GridView
似乎这个问题已经被问过很多次了,我已经阅读了很多问题和他们的答案,但其中 none 适合我的问题:
我的情况:
- 在我的 Activity 中,在一堆其他东西下面,您应该会看到一个棋盘。对于 small/short 智能手机,棋盘(正方形)剩余的 space 可能不会太多。所以我不能简单的说棋盘的大小是由剩下的宽度决定的。如果剩余高度较低则高度决定尺寸。
- 方块的数量因游戏而异。棋盘永远是正方形,但它的尺寸从 3x3 到 8x8 不等。
- 我希望使用 GridView 实现的棋盘具有黑色边框(大约 2pd)。
- 如果棋盘的方格可以是真实的方格就好了。但是我希望即使列数不同也能固定棋盘的大小。因此我不能有一个恒定的边框厚度和正方形是真正的正方形,因为棋盘的大小(减去边框厚度)不能保证被列数整除。
我看到了两种可能的解决方案来处理这个问题,但我无法让它们工作:
为了得到一个漂亮的方形棋盘,我使用了下面的xml:
<GridView
android:id="@+id/chessboard_gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="2dp"
android:layout_margin="10dp"
android:background="@color/black"
android:layout_gravity="center"
android:gravity="center" >
</GridView>
和 onCreate()
我的 activity 中的以下代码:
gridView.setNumColumns(board.getColumns());
gridView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
@Override
public void onGlobalLayout() {
int size = Math.min(gridView.getWidth(), gridView.getHeight());
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.width = size;
params.height = size;
gridView.setLayoutParams(params);
gridView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}});
为了得到完美的正方形,我找到了我的自定义适配器使用的 ImageView 的以下解决方案:
public class SquareView extends ImageView{
public SquareView(Context context){
super(context);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
}
但是,如果我看一下结果,我会发现边界线的粗细不同,因为棋盘不能被列数整除:
如果我以某种方式设法使所有方块都在 GridView 中居中,我可以接受。然后border比2dp还粗,有可能一侧比另一侧厚一个像素,不过我不在乎
问题:我怎样才能使方块居中以使边框厚度不会随延伸变化而变化?
另一种方法是有一个正好为 2 dp 的漂亮边框,但正方形并不是真正的正方形。剩余的 space 使右侧和底部的边框变粗,可以或多或少均匀地分布在正方形上。例如:如果还有 3 个剩余像素,则使第 2、4、6 列各宽一个像素,使第 2、4、6 行高一个像素。
问题:如何才能将所有 GridView space 完美地用于我的正方形,即使这意味着我的正方形不再是真正的正方形,但有些稍宽或稍高?
我原以为 GridView 会自动拉伸它们,但如果我使用简单的 ImageView 而不是我的 SquareView 作为方块,如果我不自己设置每个方块的大小,我就会得到一个黑色的棋盘。如果我手动为正方形设置正方形大小,我会得到所有 stretchModes 的不同错误结果。
希望我没看错你的问题。问题可能是由于大小不能被 board.getColumns 整除。所以我们可以选择一个 newSize,它对于给定的板列来说是可等分的。
gridView.setNumColumns(board.getColumns());
gridView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
@Override
public void onGlobalLayout() {
int size = Math.min(gridView.getWidth(), gridView.getHeight());
int newsize = (size/board.getColumns()) * board.getColumns(); // computing new size
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.width = newsize; //assigning new size
params.height = newsize; //assigning new size
gridView.setLayoutParams(params);
gridView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}});
我很久以前就问过这个问题,然后决定写下我是如何解决我的问题的。最后,我不在乎更改行数和列数时棋盘大小可能会有所不同。请注意,可能会有更新的答案。这是一个在 2015 年对我有用的解决方案。
我的网格视图:
<GridView
android:id="@+id/chessboard_gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@color/black"
android:gravity="center"
android:padding="2dp">
</GridView>
在 Activity 的 onCreate
中初始化:
this.gridView = (GridView) findViewById(R.id.chessboard_gridview);
相同的 Activity 为棋盘使用自定义适配器:
ChessboardViewAdapter adapter = new ChessboardViewAdapter(numRows, numCols, ...);
gridView.setAdapter(adapter);
ChessboardViewAdapter
然后(除其他事项外)确定正方形的适当大小。请注意,SquareView
是一个自定义 class,它不再像我最初问题中的代码那样覆盖 onMeasure
。
public class ChessboardViewAdapter extends BaseAdapter{
...
@Override
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
if(view == null){
view = new SquareView(context);
}
// Adjust each square's size to look like a square
int parentPadding = 2 * parent.getPaddingTop(); // equal paddings
int newSize = (parent.getWidth() - parentPadding) / this.columns;
view.setLayoutParams(new GridView.LayoutParams(newSize, newSize));
view.setPadding(10, 10, 10, 10); // hard coded offsets for the black border
...
}
}
似乎这个问题已经被问过很多次了,我已经阅读了很多问题和他们的答案,但其中 none 适合我的问题:
我的情况:
- 在我的 Activity 中,在一堆其他东西下面,您应该会看到一个棋盘。对于 small/short 智能手机,棋盘(正方形)剩余的 space 可能不会太多。所以我不能简单的说棋盘的大小是由剩下的宽度决定的。如果剩余高度较低则高度决定尺寸。
- 方块的数量因游戏而异。棋盘永远是正方形,但它的尺寸从 3x3 到 8x8 不等。
- 我希望使用 GridView 实现的棋盘具有黑色边框(大约 2pd)。
- 如果棋盘的方格可以是真实的方格就好了。但是我希望即使列数不同也能固定棋盘的大小。因此我不能有一个恒定的边框厚度和正方形是真正的正方形,因为棋盘的大小(减去边框厚度)不能保证被列数整除。
我看到了两种可能的解决方案来处理这个问题,但我无法让它们工作:
为了得到一个漂亮的方形棋盘,我使用了下面的xml:
<GridView android:id="@+id/chessboard_gridview" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="2dp" android:layout_margin="10dp" android:background="@color/black" android:layout_gravity="center" android:gravity="center" > </GridView>
和
onCreate()
我的 activity 中的以下代码:gridView.setNumColumns(board.getColumns()); gridView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener(){ @Override public void onGlobalLayout() { int size = Math.min(gridView.getWidth(), gridView.getHeight()); ViewGroup.LayoutParams params = gridView.getLayoutParams(); params.width = size; params.height = size; gridView.setLayoutParams(params); gridView.getViewTreeObserver().removeOnGlobalLayoutListener(this); }});
为了得到完美的正方形,我找到了我的自定义适配器使用的 ImageView 的以下解决方案:
public class SquareView extends ImageView{ public SquareView(Context context){ super(context); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); } }
但是,如果我看一下结果,我会发现边界线的粗细不同,因为棋盘不能被列数整除:
如果我以某种方式设法使所有方块都在 GridView 中居中,我可以接受。然后border比2dp还粗,有可能一侧比另一侧厚一个像素,不过我不在乎
问题:我怎样才能使方块居中以使边框厚度不会随延伸变化而变化?
另一种方法是有一个正好为 2 dp 的漂亮边框,但正方形并不是真正的正方形。剩余的 space 使右侧和底部的边框变粗,可以或多或少均匀地分布在正方形上。例如:如果还有 3 个剩余像素,则使第 2、4、6 列各宽一个像素,使第 2、4、6 行高一个像素。
问题:如何才能将所有 GridView space 完美地用于我的正方形,即使这意味着我的正方形不再是真正的正方形,但有些稍宽或稍高?
我原以为 GridView 会自动拉伸它们,但如果我使用简单的 ImageView 而不是我的 SquareView 作为方块,如果我不自己设置每个方块的大小,我就会得到一个黑色的棋盘。如果我手动为正方形设置正方形大小,我会得到所有 stretchModes 的不同错误结果。
希望我没看错你的问题。问题可能是由于大小不能被 board.getColumns 整除。所以我们可以选择一个 newSize,它对于给定的板列来说是可等分的。
gridView.setNumColumns(board.getColumns());
gridView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
@Override
public void onGlobalLayout() {
int size = Math.min(gridView.getWidth(), gridView.getHeight());
int newsize = (size/board.getColumns()) * board.getColumns(); // computing new size
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.width = newsize; //assigning new size
params.height = newsize; //assigning new size
gridView.setLayoutParams(params);
gridView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}});
我很久以前就问过这个问题,然后决定写下我是如何解决我的问题的。最后,我不在乎更改行数和列数时棋盘大小可能会有所不同。请注意,可能会有更新的答案。这是一个在 2015 年对我有用的解决方案。
我的网格视图:
<GridView
android:id="@+id/chessboard_gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@color/black"
android:gravity="center"
android:padding="2dp">
</GridView>
在 Activity 的 onCreate
中初始化:
this.gridView = (GridView) findViewById(R.id.chessboard_gridview);
相同的 Activity 为棋盘使用自定义适配器:
ChessboardViewAdapter adapter = new ChessboardViewAdapter(numRows, numCols, ...);
gridView.setAdapter(adapter);
ChessboardViewAdapter
然后(除其他事项外)确定正方形的适当大小。请注意,SquareView
是一个自定义 class,它不再像我最初问题中的代码那样覆盖 onMeasure
。
public class ChessboardViewAdapter extends BaseAdapter{
...
@Override
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
if(view == null){
view = new SquareView(context);
}
// Adjust each square's size to look like a square
int parentPadding = 2 * parent.getPaddingTop(); // equal paddings
int newSize = (parent.getWidth() - parentPadding) / this.columns;
view.setLayoutParams(new GridView.LayoutParams(newSize, newSize));
view.setPadding(10, 10, 10, 10); // hard coded offsets for the black border
...
}
}