【问题标题】:Full height square element in androidandroid中的全高方形元素
【发布时间】:2016-02-23 10:29:15
【问题描述】:

我想要一个正方形(与高度相同的宽度)GridView 以横向填充屏幕的整个高度。 Gridview 是一个带有 xml 的棋盘(8 x 8 方格):

<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> 

,其中 ImageViews 对应于棋盘的正方形和棋子(均来自 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/board 的高度(=宽度)太大。工具栏的高度和状态栏的高度太大了。如何获得合适的 GridView 尺寸,即屏幕高度减去状态栏高度减去工具栏高度?

【问题讨论】:

  • 使 heightMeasureSpec 等于窗口高度 ....

标签: android android-layout gridview landscape-portrait


【解决方案1】:

从您的布局文件的两个版本开始:

/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 维度将具有 MeasureSpec 模式 EXACTLYwrap_content 维度将具有 MeasureSpec 模式 AT_MOST。您可以使用它来实现您想要的布局。

@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 容器。请参阅我的其他答案以获取更新的测量代码。

【讨论】:

  • 这似乎对我不起作用。我只得到一行网格元素。
  • GridView 本身是正方形的吗?如果是这样,那么您可能需要做一些事情来使您的项目视图大小不同。如果您可以发布您的网格项目布局 XML 会有所帮助。
  • 感谢您的回复,我把上面网格项目的XML贴出来了,也试着澄清一下我的问题是什么。
【解决方案2】:

啊。现在我知道这是为了游戏。

有时最好有布局和子视图,但在大多数情况下,如果有游戏板,最好创建一个表示游戏视图的 View 子类。

例如,如果您的用户说他们想要捏拉缩放到游戏板的一个象限,该怎么办?你不能用 GridView 做到这一点。

我制作了一个简单的应用程序来向您展示它是如何工作的。我简化了之前发布的onMeasure() 代码,而不是GridView,而是一个View 子类呈现游戏板。

MainActivity 只是设置内容视图。

/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_parentwrap_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>

GameBoardView.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 子类主要用作控制器,解释触摸事件并更新游戏模型。

【讨论】:

    猜你喜欢
    • 2020-02-05
    • 1970-01-01
    • 1970-01-01
    • 2021-04-08
    • 2011-03-25
    • 1970-01-01
    • 2021-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多