2013-01-24 13 views
5

Sto creando una mappa isometrica con tessere semplici e io ’ ve estesa RelativeLayout per creare un layout che contenga queste tessere. In realtà, solo l'uso di un RelativeLayout as-is ha funzionato bene finché il mio orientamento corrispondeva all'ordine in cui le tessere venivano scritte nel file XML; tutti i ’ sovrascritti sono i costruttori, dove ho semplicemente chiamato super e setChildrenDrawingOrderEnabled(true); insieme con l'impostazione di alcune variabili (altezza e larghezza della griglia), e quindi getChildDrawingOrder stesso.getChildDrawingOrder chiamato/usato in modo errato?

Il mio codice per getChildDrawingOrder capisce il nuovo indice per il bambino dato, e imposta anche una stringa nel bambino a i->i', dove i è l'indice originale e i' è il nuovo indice. I ’ m utilizzando questo per il test; i bambini sono impostati per disegnare questa stringa su se stessi insieme alle loro coordinate.

Sfortunatamente, non funziona correttamente, o meglio funziona in modo irregolare. Delle nove tessere nel mio test case, tre don ’ t sembrano aver chiamato il numero getChildDrawingOrder: la stringa che ho menzionato sopra è null. Del resto, almeno uno viene disegnato fuori ordine nonostante venga passato l'indice corretto.

Qui ’ immagine sa (nell'orientamento TOP):

Image of getChildDrawingOrder failure

Si noti che (0,2), (1,2), e (2,1) sono tutti elencati come NULL, e quindi getChildDrawingOrder sembra non essere mai stato chiamato per loro. Si noti inoltre che (1,0) è disegnato sopra (1,1), anche se entrambi i numeri i (3) e i' (1) sono inferiori a (1,1) ’ s (4 e 4, rispettivamente).

Qui ’ s il codice getChildDrawingOrder:

@Override 
protected int getChildDrawingOrder(int childCount, int i) 
{ 
    TileView ch = (TileView)getChildAt(i); 
    ch.order = "Called"; // this string is drawn on my children 
    int gx, gy; // the "true" x,y for the current rotation, 
       // where 0,0 is the top corner 
    switch (rotation) 
    { 
    case TOP: 
     gx = ch.x(); 
     gy = ch.y(); 
     break; 
    case LEFT: 
     gx = (width()-1-ch.x()); 
     gy = ch.y(); 
     break; 
    case RIGHT: 
     gx = ch.x(); 
     gy = (length()-1-ch.y()); 
     break; 
    case BOTTOM: 
     gx = (width()-1-ch.x()); 
     gy = (length()-1-ch.y()); 
     break; 
    default: 
     gx = ch.x(); 
     gy = ch.y(); 
    } 
    int row = gx+gy; // current row 
    if (row == 0) // row 0 is always just the top corner and 0 
    { 
     ch.order = new String(i+"->0"); // string set to i->i' 
     return 0; 
    } 
    else 
    { 
     int mx = width()-1, // maximum x value 
      my = length()-1, // maximum y value 
      mrow = mx+my, // maximum row 
      min = Math.min(mx, my), // minor axis length 
      maj = Math.max(mx, my), // major axis length 
      retn; // for storing the return value 
     // inside the top corner 
     if (row <= min) 
     { 
      // Gauss's formula to get number of cells in previous rows 
      // plus the number for which cell in this row this is. 
      retn = row*(row+1)/2+gy; 
     } 
     // in the middle 
     else if (row <= maj) 
     { 
      // Gauss's formula to get number of cells in top corner 
      // plus the number of cells in previous rows of the middle section 
      // plus the number for which cell in this row this is. 
      retn = min*(min+1)/2+min*(row-min)+gy; 
     } 
     // bottom corner 
     else 
     { 
      retn = (min+1)*(min+2)/2 // cells in the top corner 
       + min*(maj-min) // cells in the middle 
       + (mrow-maj)*(mrow-maj+1)/2 // total cells in bottom triangle 
       - (mrow-row+1)*(mrow-row+2)/2 // less cells after this one 
       + gy // which cell in this row 
       - (row-maj) // to account for gy not starting at zero 
       ; 
     } 
     ch.order = new String(i+"->"+retn); // string set to i->i' 
     return retn; 
    } 
} 

Qualcuno può far luce su ciò che ’ sta succedendo? Perché isn ’ t getChildDrawingOrder viene chiamato per quelle tre tessere? Perché è (1,0) disegnato nell'ordine errato, anche se getChildDrawingOrderè chiamato?

risposta

10

OK, abbiamo capito guardando il codice sorgente di Android. Ho avuto la mappatura di getChildDrawingOrder: la i passata è “ quale bambino dovrei disegnare i th? ” non "quando dovrei disegnare i bambini?" Il motivo per lo NULL s è perché quei bambini venivano disegnati prima che fosse passato il loro i.

ho cambiato il mio codice per capire l'ordine per tutti i bambini durante il passaggio onMeasure, il risparmio che in un SparseIntArray, e poi basta tornati che dal getChildDrawingOrder. Questo funziona.

Il calcolo indietro dell'indice nella funzione getChildDrawingOrder, a proposito, è una cattiva idea a meno che non si voglia fare affidamento sull'ordine in cui i bambini sono dichiarati. Perché se tu fai ’ t contare su quell'ordine, devi camminare attraverso l'elenco dei bambini per trovare quello che ha i valori x e y appropriati, il che significa che devi percorrere l'elenco dei bambini per ogni bambino. Quella ’ s una operazione O (n²) (leggi: abbastanza inefficiente). Anche la matematica è ragionevolmente complicata.

1

Ecco un semplice esempio che mostra come sovrascrivere getChildDrawingOrder

  1. come un modo per regolare che dei bambini viene redatto in quale ordine (con l'ultima di essere in alto)
  2. hanno l'ordine cambiare da un rubinetto/clicca evento

La classe RelativeLayout:

public class AlternatingChildDrawingOrderRelativeLayout extends RelativeLayout { 

    // the childDrawingOrder modifier 
    private int childDrawingOrderModifier = 0; 

    public AlternatingChildDrawingOrderRelativeLayout(Context context) { 
     super(context); 
     init(context); 
    } 

    void init(Context context) { 
     setClickable(true); 
     setChildrenDrawingOrderEnabled(true); 
     setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       // increment to adjust the child drawing order 
       childDrawingOrderModifier++; 
       // call invalidate to redraw with new order modifier 
       ViewCompat.postInvalidateOnAnimation(v); 
      } 
     }); 
    } 

    @Override 
    protected int getChildDrawingOrder(int childCount, int i) { 
     // increment i with the modifier, then afford for out of bounds using modulus of the child count 
     int returnValue = (i + childDrawingOrderModifier) % childCount; 
     Log.v(VIEW_LOG_TAG, "getChildDrawingOrder returnValue=" + returnValue + " i=" + i); 
     return returnValue; 
    } 

    public AlternatingChildDrawingOrderRelativeLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     init(context); 
    } 

    public AlternatingChildDrawingOrderRelativeLayout(Context context, 
                 AttributeSet attrs, 
                 int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
     init(context); 
    } 

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 
    public AlternatingChildDrawingOrderRelativeLayout(Context context, 
                 AttributeSet attrs, 
                 int defStyleAttr, 
                 int defStyleRes) { 
     super(context, attrs, defStyleAttr, defStyleRes); 
     init(context); 
    } 

} 

Il layout xml

<?xml version="1.0" encoding="utf-8"?> 
<com.example.ui.AlternatingChildDrawingOrderRelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="300dp" 
    android:layout_height="300dp"> 

    <View 
     android:id="@+id/red" 
     android:layout_width="125dp" 
     android:layout_height="300dp" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentStart="true" 
     android:background="#f00" 
     /> 

    <View 
     android:id="@+id/green" 
     android:layout_width="125dp" 
     android:layout_height="300dp" 
     android:layout_centerInParent="true" 
     android:background="#0f0"/> 

    <View 
     android:id="@+id/blue" 
     android:layout_width="125dp" 
     android:layout_height="300dp" 
     android:layout_alignParentRight="true" 
     android:layout_alignParentEnd="true" 
     android:background="#00f"/> 

</com.example.ui.AlternatingChildDrawingOrderRelativeLayout> 

Come appare

Starting Draw order (blue) First tap (red) Second tap (green

Nella foto a sinistra è l'ordine di partenza di disegno, che è il default basata su il layout xml:

Red = index 0 
Green = index 1 
Blue = index 2 

Quindi dal primo all'ultimo (o pensa dal basso verso l'alto) cioè: rosso, verde, blu. Qui è il dump registro di getChildDrawingOrder chiamato

V/View: getChildDrawingOrder returnValue=0 i=0 
V/View: getChildDrawingOrder returnValue=1 i=1 
V/View: getChildDrawingOrder returnValue=2 i=2 

Nel mezzo, dopo il nostro primo rubinetto, i cambiamenti al fine di verde, blu, rosso

V/View: getChildDrawingOrder returnValue=1 i=0 
V/View: getChildDrawingOrder returnValue=2 i=1 
V/View: getChildDrawingOrder returnValue=0 i=2 

E, sul lato destro ci mostra che cos'è sembra che dopo il nostro secondo tocco da quando l'ordine è cambiato in: blu, rosso, verde.

V/View: getChildDrawingOrder returnValue=2 i=0 
V/View: getChildDrawingOrder returnValue=0 i=1 
V/View: getChildDrawingOrder returnValue=1 i=2 

Qualsiasi rubinetto dopo Questo più o meno cicli di nuovo all'ordine originale dove il blu era ultimo a essere redatta a causa del calcolo del modulo

HTHS!

+0

Mi sembra che questo abbia bisogno di un po 'più di introduzione. Sono stato lontano da sviluppo Android per anni, quindi dovrei scavare un po 'per entrare in questo codice e capire cosa stava facendo. Senza farlo, non posso nemmeno dire se questa è una buona risposta. Altre spiegazioni su 'getChildDrawingOrder' e su come funziona/su come sono utilizzate potrebbero essere d'aiuto, penso. – KRyan

+0

Aggiungerò alcune immagini per illustrare – petey

Problemi correlati