Android Hexagon网格 [英] Android Hexagon Grid

查看:112
本文介绍了Android Hexagon网格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要开发一个应用程序,其中的按钮是六边形的,并且所有这些应用程序都彼此相邻放置以创建网格。鉴于我在Android中的一些经验,我不知道GridView是否是最好的方法。如果是这样的话,我怎么能把六边形放在一起呢?



我现在有这个


在main.xml中使用此布局:

 <?xml version =1.0encoding =utf-8?> 
< GridView xmlns:android =http://schemas.android.com/apk/res/android
android:id =@ + id / gridview
android:layout_width =fill_parent
android:layout_height =fill_parent
android:padding =0dp
android:verticalSpacing =0dp
android:horizo​​ntalSpacing =0dp
android:numColumns =4
android:columnWidth =0dp
android:stretchMode =columnWidth
android:gravity =top
/>

这就是我想要得到的结果:





我需要一些帮助将六边形相互固定在一个固定的结构中。我一直在玩布局值,没有成功。 TableView会是一个更好的方法吗?
非常感谢

解决方案

这是我在应用程序中使用的一些代码(它被称为'Connect3'我喜欢玩:))。这是一个自定义布局类,可以在网格中绘制六角形图像。该网格可以是三角形或倾斜的矩形。



该代码计算每个图像视图的边界(以像素为单位)(相对于hexgrid的起点),然后调用 imageView.layout(left,top,right,bottom)来设置计算范围。计算并不困难。主要参数是六角形的半径。由此,总高,总宽度,有效高度和有效宽度(imageview的高度/宽度分别是两个连续视图的顶部/左边界之间的距离)。然后归结为一些简单的循环来绘制它们。

要使视图可点击,只需在创建视图时设置 onClickListener 即可。 (我把它变成了一个类的成员,因为它让事情变得更容易)。
$ b

onMeasure 函数只计算总数视图的宽度和高度,并使用这些值调用 setMeasuredDimension



用于所有这些的图像只是单个六边形,就像您在操作栏下方看到的一样。请注意,图像是正方形。

  @Override 
保护void onLayout(final boolean changed,final int l,final int t,final int r,final int b){
Log.d(TAG,board.onlayout called with size+ mSize +l:+ l +r:+ r +t:+ t + b:+ b);

//如果电路板的尺寸没有变化,则不需要重绘。只需通过调用invalidate()来更新视图的图像即可。
if(!changed&&!mSizeInvalidated){
invalidate();
return;
}
int childCount = getChildCount();

//计算一些有用的参数。
float radius = getResources()。getDimension(R.dimen.radius);
float verticalMargin = -radius / 4;
float horizo​​ntalMargin =((float)Math.sqrt(3)/ 2 - 1)* radius;
float height = 2 * radius;
float width = height;
float effectiveHeight = height + 2 * verticalMargin;
float effectiveWidth = width + 2 * horizo​​ntalMargin;

float totalHeight =(radius *(3 * mSize + 1))/ 2;
float totalWidth;
switch(mGameType){
case Connect3Turn.GAME_TYPE_HEX:
totalWidth =(((float)mSize * 3 - 1)/ 2)*((float)Math.sqrt(3)) *半径;
休息;
case Connect3Turn.GAME_TYPE_Y:
default:
totalWidth = mSize *((float)Math.sqrt(3))* radius;


LayoutParams layoutParams = new LayoutParams((int)width,(int)height);

//用于计算水平和垂直居中偏移量的代码(这是.xml文件中的一个选项)
// GAME_TYPE_HEX创建倾斜矩形板,GAME_TYPE_Y创建三角板。
float x_offset_row;
switch(mGameType){
case Connect3Turn.GAME_TYPE_Y:
x_offset_row =(mSize - 1)* effectiveWidth / 2 + horizo​​ntalMargin;
休息;
案例Connect3Turn.GAME_TYPE_HEX:
默认值:
x_offset_row = 0;
}
switch(mCenterHorizo​​ntal){
//网格的左侧应该位于非负坐标处。
案例1:{
x_offset_row + = Math.max(0,(r-1-totalWidth)/ 2);
休息;
}
情况2:{x_offset_row + = Math.max(0,(r-1-totalWidth));
休息;
}
案例0:
默认值:{
break;
}
}

//计算垂直居中的y_offset。
float y_offset = 0;
switch(mCenterVertical){
case 1:{
y_offset = Math.max(0,(b - t - totalHeight)/ 2);
休息;
}
案例2:{
y_offset = Math.max(0,(b - t -totalHeight));
休息;
}
}


int cell = 0;
for(int row = 0; row< mSize; ++ row){
float x_offset = x_offset_row;
int rowLength;
//行长取决于我们想绘制的棋盘类型。
switch(mGameType){
case Connect3Turn.GAME_TYPE_HEX:
rowLength = mSize;
休息;
case Connect3Turn.GAME_TYPE_Y:
默认值:
rowLength = row + 1;
}
Log.d(TAG,绘制行+ row +加上+ rowLength +单元格。);
for(int col = 0; col< rowLength; ++ col){
ImageView v;
if(cell< childCount){
v =(ImageView)getChildAt(cell);
} else {
v = new ImageView(super.getContext());
v.setLayoutParams(layoutParams);
v.setOnClickListener(onClickListener);
addViewInLayout(v,cell,v.getLayoutParams(),true);
}

//设置单元格的图像(颜色),并将其索引放入标记中,以便我们可以检索onClickListener中单击单元格的数量。
v.setImageResource(mImageIds [mImages [cell]]);
v.setTag(cell);

//设置图像的边界,将在可用空间中自动裁剪。
v.layout((int)x_offset,(int)y_offset,(int)(x_offset + width),(int)(y_offset + height));
x_offset + = effectiveWidth;
++ cell;
}
y_offset + = effectiveHeight;
//下一行的偏移量,相对于这个偏移量,又取决于游戏类型。
switch(mGameType){
case Connect3Turn.GAME_TYPE_Y:
x_offset_row - = effectiveWidth / 2;
休息;
case Connect3Turn.GAME_TYPE_HEX:
x_offset_row + = effectiveWidth / 2;
}
}

//我们更新了所有视图,因此它不再失效。
mSizeInvalidated = false;
}


I need to develop an app in which buttons are hexagons and all of them are placed next to each other creating a grid. Given my little experience in Android, I wonder if GridView is the best approach for this. If that is the case, how could I place the hexagons next to each other?

I have this by now

Using this layout in main.xml:

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/gridview"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:padding="0dp"
    android:verticalSpacing="0dp"
    android:horizontalSpacing="0dp"
    android:numColumns="4"
    android:columnWidth="0dp"
    android:stretchMode="columnWidth"
    android:gravity="top"
/>

And this is what I am trying to get:

I would need some help to place hexagons tied to each other in a fixed structure. I've been playing around with the layout values with no sucess. Would TableView be a better approach? Thanks a lot

解决方案

Here is some code I used in an app (it's called 'Connect3, if you'd like to play it :) ). It is a custom layout class that draws hexagonal images in a grid. The grid can be triangular or a tilted rectangle.

The code calculates the bounds (in pixels relative to the origin of the hexgrid) of each imageview and then calls imageView.layout(left,top,right,bottom) to set the calculated bounds. The calculations aren't that hard. The main parameter is the radius of the hexagon. From that, the total hight, total width, effective hight and effective width (the height/width of the imageview respectively the distance between the top/left bounds of two consecutive views). Then it comes down to some simple for loops to draw them.

To make the views clickable, just set an onClickListener when you create them. (I made it a class member, because it made things easier).

The onMeasure functions just calculates the total width and height of the view and calls setMeasuredDimension with those values.

The images used for all this are just the single hexagons as you see them right below the actionbar. Note that the images are squares.

    @Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) {
    Log.d(TAG, "board.onlayout called with size "+mSize+" l: "+l+" r: "+r+" t: "+t+" b: "+b);

    //If the dimensions of the board haven't changed, a redraw isn't necessary. Just update the images of the views instead by calling invalidate().
    if (!changed && !mSizeInvalidated) {
        invalidate();
        return;
    }
    int childCount = getChildCount();

    //Calculate some useful parameters.
    float radius = getResources().getDimension(R.dimen.radius);
    float verticalMargin = -radius / 4;
    float horizontalMargin = ((float) Math.sqrt(3) / 2 - 1) * radius;
    float height = 2 * radius;
    float width = height;
    float effectiveHeight = height + 2 * verticalMargin;
    float effectiveWidth = width + 2 * horizontalMargin;

    float totalHeight=(radius * (3 * mSize + 1)) / 2;
    float totalWidth;
    switch (mGameType) {
        case Connect3Turn.GAME_TYPE_HEX:
            totalWidth = (((float) mSize * 3  - 1)/ 2) * ((float) Math.sqrt(3)) * radius;
            break;
        case Connect3Turn.GAME_TYPE_Y:
        default:
            totalWidth = mSize * ((float) Math.sqrt(3)) * radius;
    }

    LayoutParams layoutParams = new LayoutParams((int) width, (int) height);

    //Code to calculate the offsets for horizontal and vertical centering (this is an option in the .xml file)
    //The GAME_TYPE_HEX creates a tilted rectangular board and GAME_TYPE_Y creates a triangular board.
    float x_offset_row;
    switch (mGameType) {
        case Connect3Turn.GAME_TYPE_Y:
            x_offset_row=(mSize - 1) * effectiveWidth / 2 + horizontalMargin;
            break;
        case Connect3Turn.GAME_TYPE_HEX:
        default:
            x_offset_row=0;
    }
    switch (mCenterHorizontal) {
        //the left side of the grid should be at non-negative coordinates.
        case 1: {
            x_offset_row += Math.max(0,(r-l-totalWidth)/2);
            break;
        }
        case 2: {x_offset_row += Math.max(0,(r-l-totalWidth));
            break;
        }
        case 0:
        default: {
            break;
        }
    }

    //calculate the y_offset for vertical centering.
    float y_offset = 0;
    switch (mCenterVertical) {
        case 1: {
            y_offset = Math.max(0, (b - t - totalHeight) / 2);
            break;
        }
        case 2: {
            y_offset = Math.max(0, (b - t -totalHeight));
            break;
        }
    }


    int cell = 0;
    for (int row = 0; row < mSize; ++row) {
        float x_offset = x_offset_row;
        int rowLength;
        //The row length depends on the board-type we want to draw.
        switch (mGameType){
            case Connect3Turn.GAME_TYPE_HEX:
                rowLength=mSize;
                break;
            case Connect3Turn.GAME_TYPE_Y:
            default:
                rowLength=row+1;
        }
        Log.d(TAG, "Drawing row "+row+" with "+rowLength+" cells.");
        for (int col = 0; col < rowLength; ++col) {
            ImageView v;
            if (cell < childCount) {
                v = (ImageView) getChildAt(cell);
            } else {
                v = new ImageView(super.getContext());
                v.setLayoutParams(layoutParams);
                v.setOnClickListener(onClickListener);
                addViewInLayout(v, cell, v.getLayoutParams(), true);
            }

            //Set the image (color) of the cell and put its index in a tag, so we can retrieve the number of the clicked cell in the onClickListener.
            v.setImageResource(mImageIds[mImages[cell]]);
            v.setTag(cell);

            //Set the bounds of the image, which will automatically be cropped in the available space.
            v.layout((int) x_offset, (int) y_offset, (int) (x_offset + width), (int) (y_offset + height));
            x_offset += effectiveWidth;
            ++cell;
        }
        y_offset += effectiveHeight;
        //The offset of the next row, relative to this one, again depends on the game type.
        switch(mGameType){
            case Connect3Turn.GAME_TYPE_Y:
                x_offset_row -= effectiveWidth / 2;
                break;
            case Connect3Turn.GAME_TYPE_HEX:
                x_offset_row += effectiveWidth / 2;
        }
    }

    //We updated all views, so it is not invalidated anymore.
    mSizeInvalidated=false;
}

这篇关于Android Hexagon网格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆