我想有一个正方形(宽度与高度相同)GridView以横向填充屏幕的整个高度。网格视图是一个棋盘(8 x 8 个正方形),带有 xml:
<com.example.jens.jchess2.view.MyGridView
android:id="@+id/chessboard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="0dp"
android:numColumns="8"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp">
</com.example.jens.jchess2.view.MyGridView>
网格的元素是:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/square"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#000080"
android:orientation="vertical"
android:padding="0pt">
<ImageView
android:id="@+id/square_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:padding="0pt" />
<ImageView
android:id="@+id/piece"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:padding="0pt" />
</FrameLayout>
,其中图像视图对应于棋盘的正方形和碎片(均来自 png 图像)。
在自定义 MyGridView 中,我按如下方式覆盖 onMeasure:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = getContext().getResources().getDisplayMetrics().heightPixels;
if (width > height) {
super.onMeasure(
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
);
} else {
super.onMeasure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY)
);
}
}
这为我提供了纵向和横向的方形网格视图。在纵向模式下,它会填充整个宽度,一切都很好。但是,在横向模式下,它会延伸到屏幕下方,因为 GridView/板的高度 (=宽度) 太大。它太大了,而不是工具栏的高度和状态栏的高度。如何获得 GridView 的正确大小,即屏幕高度减去状态栏高度减去工具栏高度?
从布局文件的两个版本开始:
/res/layout/grid.xml
...
<!-- full width -->
<com.example.MyGridView
android:layout_width="match_parent"
android:layout_height="wrap_content"
...
/>
...
/res/layout-land/grid.xml
...
<!-- full height -->
<com.example.MyGridView
android:layout_width="wrap_content"
android:layout_height="match_parent"
...
/>
...
你可能已经有了这样的东西。
现在,在onMeasure()
覆盖中,match_parent
维度将具有EXACTLY
MeasureSpec
模式,wrap_content
维度将具有AT_MOST
MeasureSpec
模式。 您可以使用它来实现所需的布局。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.AT_MOST) {
// portrait
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
} else if (heightMode == MeasureSpec.EXACTLY && widthMode == MeasureSpec.AT_MOST) {
// landscape
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
编辑:我发现这两种模式都可以AT_MOST,具体取决于ViewGroup
容器。 请参阅我的另一个答案以获取更新的测量代码。
啊。现在我看到这是为了一个游戏。
有时最好有布局和子视图,但在大多数情况下,对于游戏板,最好创建一个表示游戏视图的View
子类。
例如,如果您的用户说他们希望能够捏合缩放到游戏板的一个象限,该怎么办? 你不能用GridView
做到这一点.
我制作了一个简单的应用程序来向您展示它是如何工作的。 我简化了之前发布的onMeasure()
代码,而不是GridView
,一个View
子类来渲染游戏板。
主活动只是设置内容视图。
/res/layout/activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.gameboard.MainActivity">
<com.example.gameboard.GameBoardView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
/res/layout-land/activity_main.xml:
请注意,match_parent
和wrap_content
的宽度和高度是切换的。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.gameboard.MainActivity">
<com.example.gameboard.GameBoardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true" />
</RelativeLayout>
游戏板视图.java:
public class GameBoardView extends View {
private Paint mPaint;
public GameBoardView(Context context) {
super(context);
}
public GameBoardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GameBoardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public GameBoardView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int size = Math.min(width, height);
int sizeMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
super.onMeasure(sizeMeasureSpec, sizeMeasureSpec);
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int w = getWidth() / 8;
int h = getHeight() / 8;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
// choose black or white depending on the square
mPaint.setColor((row + col) % 2 == 0 ? 0xFFFFFFFF : 0xFF000000);
canvas.drawRect(w * col, h * row, w * (col + 1), h * (row + 1), mPaint);
}
}
}
}
在这里,我只是在视图中绘制正方形。 现在,如果我正在制作国际象棋游戏,我还将创建一个 Drawable
子类,该子类将采用游戏模型并呈现它。 使用单独的Drawable
来渲染游戏可以轻松缩放到正确的大小。 例如,Drawable
可以以固定的常量大小呈现,然后按View
子类进行缩放以适合。 View
子类将主要用作控制器,解释触摸事件并更新游戏模型。