在Android中绘制动态自定义视图棋盘
Posted
技术标签:
【中文标题】在Android中绘制动态自定义视图棋盘【英文标题】:Drawing a dynamic custom view chess board in Android 【发布时间】:2018-09-08 13:26:35 【问题描述】:我想在 android studio 中使用 canvas 和 通过覆盖方法 onDraw 动态绘制一个 8 x 8 棋盘,我几乎成功了,但我遇到了一个很烦人的问题。
我已经制作了一个自定义视图,我的目标是使父布局与其子自定义视图的大小相匹配,这样我的棋盘就可以覆盖整个屏幕。 (在 XML 文件中,父子节点都设置为 match_parent)
我希望棋盘也能覆盖整个屏幕高度。
查看下图这是我得到的结果,注意下部区域的巨大间隙,我的目的是垂直拉伸棋盘并使其覆盖整个屏幕以消除该空间。
这是我到目前为止设法写的,但它没有做我想要的: 类棋盘:
public class ChessBoard extends View
private static final String TAG = ChessBoard.class.getSimpleName();
private Rect rect;
private static final int COLS = 8;
private static final int ROWS = 8;
Tile tile;
private final Tile[][] mTiles;
private int x0 = 0;
private int y0 = 0;
private static final int DEF_SQUARE_SIZE=50;
private int squareSize=0;
private boolean flipped = false;
public ChessBoard(final Context context,AttributeSet attrs)
super(context,attrs);
this.mTiles = new Tile[COLS][ROWS];
buildTiles();
rect=new Rect();
onDraw 方法:
protected void onDraw(final Canvas canvas)
int width = getWidth();
int height = getHeight();
squareSize=Math.min(getSquareSizeWidth(width),getSquareSizeHeight(height));
computeOrigins(width,height);
for (int c = 0; c < COLS; c++)
for (int r = 0; r < ROWS; r++)
final int xCoord = getXCoord(c);
final int yCoord = getYCoord(r);
mTiles[c][r].setTileRect(rect);
rect.left=xCoord;
rect.top=yCoord;
rect.right= rect.left+squareSize; // right
rect.bottom=rect.top + squareSize;
mTiles[c][r].draw(canvas);
类图块:
public final class Tile
private static final String TAG = Tile.class.getSimpleName();
private final int col;
private final int row;
private final Paint squareColor;
private Rect tileRect;
public Tile(final int col, final int row)
this.col = col;
this.row = row;
this.squareColor = new Paint();
squareColor.setColor(isDark() ? Color.BLACK : Color.WHITE);
squareColor.setAntiAlias(true);
public void draw(final Canvas canvas)
canvas.drawRect(tileRect, squareColor);
public String getColumnString()
switch (col)
case 0: return "A";
case 1: return "B";
case 2: return "C";
case 3: return "D";
case 4: return "E";
case 5: return "F";
case 6: return "G";
case 7: return "H";
default: return null;
public String getRowString()
// To get the actual row, add 1 since 'row' is 0 indexed.
return String.valueOf(row + 1);
public void handleTouch()
Log.d(TAG, "handleTouch(): col: " + col);
Log.d(TAG, "handleTouch(): row: " + row);
public boolean isDark()
return (col + row) % 2 == 0;
public boolean isTouched(final int x, final int y)
return tileRect.contains(x, y);
public void setTileRect(final Rect tileRect)
this.tileRect = tileRect;
public String toString()
final String column = getColumnString();
final String row = getRowString();
return "<Tile " + column + row + ">";
onMeasure 方法:
protected void onMeasure(int widthMeasureSpec, int
heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
int sqSizeW = getSquareSizeWidth(width);
int sqSizeH = getSquareSizeHeight(height);
int sqSize = Math.min(sqSizeW, sqSizeH);
if (height > width)
int p = getMaxHeightPercentage();
height = Math.min(getHeight(sqSize), height * p / 100);
else
width = Math.min(getWidth(sqSize), width * 65 / 100);
setMeasuredDimension(width, height);
Class ChessBoard 方法:
protected int getWidth(int sqSize)
return sqSize * 8;
protected int getHeight(int sqSize)
return sqSize * 8;
private int getSquareSizeWidth(final int width)
return (width)/ 8;
private int getSquareSizeHeight(final int height)
return (height)/8;
private int getXCoord(final int x)
return x0 + squareSize * (flipped ? 7 - x : x);
private int getYCoord(final int y)
return y0 + squareSize * (flipped ? y : 7 - y);
private void computeOrigins(final int width, final int height)
this.x0 = (width - squareSize *8)/2 ;
this.y0 = (height - squareSize *8)/2;
protected int getMaxHeightPercentage()
return 75;
请注意,上面的 onDraw 方法是在 Chess Board 类中实现的。
我确定这个问题的解决方案在于 onMeasure 方法,我在想如果我增加每个方块的高度,那么棋盘会水平伸展并覆盖整个屏幕吗?谁能告诉我我做错了什么?
【问题讨论】:
【参考方案1】:嗯,不太确定你想通过一个非方形棋盘来实现什么,这不是它通常的表示方式。无论如何,只是以某种方式查看您的代码,以下几行看起来有点可疑:
squareSize=Math.min(getSquareSizeWidth(width),getSquareSizeHeight(height));
和
rect.right= rect.left+squareSize; // right
rect.bottom=rect.top + squareSize;
因此,您的平铺矩形似乎总是设置为相同的宽度和高度,根据这些线,这是宽度和高度的最小值。
【讨论】:
不,我不想要一个非方形的棋盘。如您所见,我以通常的形式动态绘制棋盘没有问题。问题是棋盘没有覆盖整个屏幕。请检查我发布的图片。你看到棋盘下面的那个空白了吗?我的问题是:我怎样才能使方块足够大,让棋盘覆盖整个屏幕? 你的问题仍然在于我上面提到的那一行。你应该使用Math.max
而不是Math.min
来覆盖屏幕。只是您可能希望将其添加到滚动视图中以获得更合理的 UI。
顺便说一句,您编写的代码与 Droid Fish 代码(由 Perter Osterlund 编写)非常相似。如果您确实修改了该代码,请确保至少注明原作者。
我只是用代码来练习,对动态自定义视图有更好的理解,谢谢提醒以上是关于在Android中绘制动态自定义视图棋盘的主要内容,如果未能解决你的问题,请参考以下文章