2014-04-15 14 views
7

Un layout alveare dovrebbe essere cosìÈ possibile creare un layout XML alveare in Android?

Le arnie colorate sono solo così si capire come devo definire gli elementi.

Quale widget Layout suggerisci di utilizzare?

Ho provato con GridView ma non riesco a creare tali celle, quindi FrameLayout ma non desidero occuparmi dei valori di pixel (o dp) quando si imposta la posizione di hive.

Sono alla fine del mio ingegno. Sono vicino alla conclusione che qualcosa come questo non può essere fatto in Android in un modo di alta qualità e senza usare librerie di gioco. Spero che qualcuno mi dia una buona idea di soluzione.

+1

Hai davvero destato la mia curiosità e ho fatto qualche ricerca su google, chiedendomi se fosse possibile. Tutto indica che no, non lo è (cioè, non con mezzi semplici), e layout non rettangolari sono raggiunti solo da "barare", come http://stackoverflow.com/a/13879492/168719 o http://stackoverflow.com/a/19583072/168719 - in altre parole, sono fatti solo per apparire non rettangolari e facendo clic nell'area trasparente viene semplicemente ignorato per mantenere quell'impressione. Nel tuo caso però dovrebbe essere delegato alla tessera adiacente, e dovendo gestire questo complicherebbe ulteriormente il codice. –

+0

Potresti forse "imbrogliare" sottoclassi una "vista", disegnando l'alveare con un 'percorso' esagonale, usando il metodo' offset() 'che scorre attraverso le righe, riempiendole ognuna con un _secondo valore RGB differente, quindi controllando quel valore dai coords in 'onTouchEvent()'? (Inoltre, penso che sia più di una forma a nido d'ape, che è un po 'appropriato.) –

+1

Immagino che potresti anche determinare in quale area si trova il tocco attraverso il semplice numero di crunch, ma è più matematica di quanto vorrei fare. __Modifica: __ Qualcuno ha già fatto i calcoli e in Java! http://www.gdreflections.com/2011/02/hexagonal-grid-math.html –

risposta

6

Poiché non sono certo dello scopo o dei requisiti previsti, quanto segue è semplicemente una prova di concetto. La classe HoneycombView non ha controlli di argomenti illegali o gestione di eccezioni di alcun tipo, in realtà. La maggior parte delle proprietà sono "hardcoded", come il colore e la larghezza delle pareti, i colori e l'orientamento delle celle, ecc. Queste sono facilmente modificabili con l'aggiunta di setter e getter appropriati. Ho incluso una semplice classe Activity per dimostrarne l'utilizzo.

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

E il 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)); 
    } 
} 

Sample image

sono andato con il mio suggerimento iniziale di un po 'alterare il colore di una superficie per determinare dove si sarebbe verificato eventi touch, ma ho finito per fare in modo di un membro Bitmap quindi i colori sullo schermo non sono interessati. Come puoi vedere dal codice, le celle in questo Bitmap sono riempite in modo tale da codificare informazioni di cella rilevanti nei componenti RGB di. Il componente rosso è impostato su 1 per indicare che un dato pixel si trova all'interno della regione pertinente (cioè nell'intero "nido d'ape"). Le posizioni di colonna e riga della cella all'interno della griglia vengono quindi codificate nei componenti Verde e Blu e sono facilmente recuperabili nel metodo onTouchEvent().

Il metodo initialize() imposta il numero di colonne e righe nella griglia e nell'esempio Activity sono impostati per favorire un orientamento orizzontale. Solo per chiarezza, nella mia implementazione, con le celle orientate in modo che l'asse lungo sia orizzontale, definisco una riga composta dalle celle i cui assi sono co-lineari. Il link che avevo postato nel mio commento ha fatto le cose in modo diverso.

Ho quasi dimenticato di dare credito: ho ottenuto il codice esagonale Path da this question.

+0

È scorrevole? –

+0

Non così com'è, ma immagino che potresti avvolgerlo in un 'ScrollView' senza troppi problemi. Non l'ho provato, però. –

+0

Ok. Cercherò. Grazie a tutti –

Problemi correlati