¿Posible hacer un diseño XML de colmena en Android?

Un diseño de colmena debería ser así

Las colmenas coloreadas son sólo para que entiendas cómo tengo que establecer elementos.

¿Qué widget de Layout sugieres de usar?

Intenté con GridView pero no puedo hacer tales células, entonces FrameLayout pero no quiero ocuparse de los valores del pixel (o del dp) al fijar la localización de la colmena.

Estoy en mi ingenio final. Estoy cerca de la conclusión de que algo así no se puede hacer en Android de una manera de alta calidad y sin el uso de bibliotecas como el juego. Espero que alguien me dé una pista buena a la solución.

Como no estoy seguro del propósito o requisitos previstos, lo siguiente es meramente prueba de concepto. La clase HoneycombView no tiene chequeos de argumentos ilegales, o manejo de excepciones de ningún tipo, realmente. La mayoría de las propiedades son "codificadas", como el color y el ancho de la pared, los colores y la orientación de las celdas, etc. Todos estos son fácilmente modificados con la adición de los setters y getters apropiados. He incluido una clase de Activity simple para demostrar su uso.

 public class HoneycombView extends View { private Paint wallPaint = new Paint(); private Paint fillPaint = new Paint(); private Paint cachePaint = new Paint(); private Path combPath; private Bitmap cacheBmp; private Canvas cacheCan; private int cellWidth; private int columns; private int rows; private boolean[][] cellSet; private OnCellClickListener listener; public HoneycombView(Context context) { this(context, null); } public HoneycombView(Context context, AttributeSet attrs) { super(context, attrs); wallPaint.setColor(Color.YELLOW); wallPaint.setStyle(Paint.Style.STROKE); wallPaint.setStrokeWidth(5f); fillPaint.setStyle(Paint.Style.FILL); cachePaint.setStyle(Paint.Style.FILL); } public void initialize(int columns, int rows) { this.columns = columns; this.rows = rows; this.cellSet = new boolean[columns][rows]; } public interface OnCellClickListener { public void onCellClick(int column, int row); } public void setOnCellClickListener(OnCellClickListener listener) { this.listener = listener; } public void setCell(int column, int row, boolean isSet) { cellSet[column][row] = isSet; invalidate(); } public boolean isCellSet(int column, int row) { return cellSet[column][row]; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); cacheBmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); cacheCan = new Canvas(cacheBmp); cellWidth = 2 * w / (2 * columns + columns - 1); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.WHITE); boolean oddRow; int xOff; combPath = getHexPath(cellWidth / 2f, cellWidth / 2f, (float) (cellWidth * Math.sqrt(3) / 4)); for (int r = 0; r < rows; r++) { oddRow = (r & 1) == 1; xOff = 0; for (int c = 0; c < columns; c++) { if (!(oddRow && c == columns - 1)) { fillPaint.setColor(cellSet[c][r] ? Color.RED : Color.WHITE); canvas.drawPath(combPath, fillPaint); canvas.drawPath(combPath, wallPaint); cachePaint.setColor(Color.argb(255, 1, c, r)); cacheCan.drawPath(combPath, cachePaint); combPath.offset((int) (1.5f * cellWidth), 0); xOff += 1.5f * cellWidth; } } combPath.offset(-xOff + (oddRow ? -1 : 1) * 3 * cellWidth / 4, (float) (cellWidth * Math.sqrt(3) / 4)); } } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() != MotionEvent.ACTION_DOWN) return true; int pixel = cacheBmp.getPixel((int) event.getX(), (int) event.getY()); int r = Color.red(pixel); if (r == 1) { int g = Color.green(pixel); int b = Color.blue(pixel); if (listener != null) { listener.onCellClick(g, b); } } return true; } private Path getHexPath(float size, float centerX, float centerY) { Path path = new Path(); for (int j = 0; j <= 6; j++) { double angle = j * Math.PI / 3; float x = (float) (centerX + size * Math.cos(angle)); float y = (float) (centerY + size * Math.sin(angle)); if (j == 0) { path.moveTo(x, y); } else { path.lineTo(x, y); } } return path; } } 

Y la Activity :

 public class MainActivity extends Activity implements HoneycombView.OnCellClickListener { HoneycombView honey; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().requestFeature(Window.FEATURE_NO_TITLE); honey = new HoneycombView(this); honey.initialize(4, 8); honey.setOnCellClickListener(this); setContentView(honey); } @Override public void onCellClick(int column, int row) { honey.setCell(column, row, !honey.isCellSet(column, row)); } } 

Imagen de muestra

Fui con mi sugerencia inicial de alterar ligeramente el color de un área para determinar dónde ocurrirían los eventos de toque, pero terminé haciéndolo en un Bitmap miembro para que los colores en pantalla no se vean afectados. Como se puede ver en el código, las celdas de este Bitmap se rellenan de tal manera que codifican información de celda relevante en los componentes RGB del Color . El componente Rojo se establece en 1 para indicar que un píxel dado está dentro de la región pertinente (es decir, dentro de todo el "nido de abeja"). La columna de la celda y las posiciones de fila dentro de la cuadrícula se codifican en los componentes Verde y Azul y se recuperan fácilmente en el método onTouchEvent() .

El método initialize() establece el número de columnas y filas en la cuadrícula y en la Activity muestra se establecen para favorecer una orientación horizontal. Sólo para mayor claridad, en mi implementación, con las celdas orientadas para que el eje largo sea horizontal, defino una fila para que conste de las celdas cuyos ejes son co-lineales. El enlace que había publicado en mi comentario hizo las cosas de manera diferente.

Casi se me olvidó dar crédito: Tengo el código de Path hexagonal de esta pregunta .

  • ¿Cuál es una buena manera de probar los métodos onMeasure / onLayout / onDraw de una vista personalizada?
  • Fondo de Android con degradado y la imagen de mosaico
  • Android adjustpan no funciona después de la primera vez
  • Analizar Google plus login
  • ¿El inflador requiere el contexto de la Actividad?
  • ¿Qué puedo hacer cuando obtengo un error "no se puede resolver con un tipo"?
  • Android ScrollView y los botones en la parte inferior de la pantalla
  • Uso del espacio de nombres de la aplicación en estilo
  • Android singleLine vs maxLines
  • Intentar obtener valores de atributo en código devuelve valores incorrectos
  • ¿Por qué mi diseño se redibuja completamente cuando invalido una de sus vistas?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.