Сетка Шестиугольника Андроида

Мне нужно разработать приложение, в котором кнопки шестигранники и все они находятся рядом друг с другом, создавая сетку. Учитывая мой небольшой опыт работы в Android, я задаюсь вопросом, является ли GridView лучшим подходом для этого. Если это так, то как я могу разместить шестиугольники рядом друг с другом?

У меня уже есть это

enter image description here

используя этот макет в 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"
/>

и это то, что я пытаюсь получить:

hexagon grid

Мне нужна помощь, чтобы разместить шестиугольники, связанные друг с другом в фиксированной структуре. Я играл со значениями макета без успеха. Будет ли TableView лучшим подходом? Большое спасибо

3 ответов


вот код, который я использовал в приложении (он называется 'Connect3, если вы хотите его воспроизвести :) ). Это пользовательский класс макета, который рисует шестиугольные изображения в сетке. Сетка может быть треугольной или наклонной.

код вычисляет границы (в пикселях относительно начала hexgrid) каждого imageview, а затем вызывает imageView.layout(left,top,right,bottom) для установки вычисляемых границ. Расчеты не так уж сложны. Основным параметром является radius шестиугольника. От этого всего высота, общая ширина, эффективная высота и эффективная ширина (высота/ширина изображения соответственно расстояние между верхней/левой границами двух последовательных видов). Тогда это сводится к некоторым простым для петель, чтобы нарисовать их.

чтобы сделать представления кликабельными, просто установите onClickListener когда вы создаете их. (Я сделал его членом класса, потому что это упростило дело).

на onMeasure функции просто вычисляет общую ширину и высоту представления и вызывает setMeasuredDimension С та ценность.

изображения, используемые для всего этого, - это только одиночные шестиугольники, как вы видите их прямо под панелью действий. Обратите внимание, что изображения являются квадратами.

    @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;
}

hexgrid1hexgrid2


Hexgrid это проект Github, который реализует шестигранную (шестигранную) сетку.


вы всегда можете работать с ним, как если бы это была нормальная сетка. Но вместо квадрата вы рисуете шестиугольник.

http://img811.imageshack.us/img811/9229/uyje.png

но затем вы перемещаете нечетные линии на половину ширины шестиугольника таким образом, чтобы они соответствовали линиям пары.

http://img822.imageshack.us/img822/2298/e5cq.png