2011-09-15 15 views
6

Estoy escribiendo una aplicación con el único propósito de tratar de entender cómo funciona la jerarquía de vista en Android. Estoy teniendo algunos problemas realmente duros en este momento. Trataré de ser conciso en mi explicación aquí.Intentando comprender la jerarquía de vista

Configuración:

Actualmente tengo tres vistas. 2 son ViewGroups y 1 es solo View. Digamos que son en este orden:

TestA extends ViewGroup 
    TestB extends ViewGroup 
    TestC extends View 
    TestA->TestB->TestC 
    Where TestC is in TestB and TestB is in TestA. 

En mi Activity simplemente mostrar los puntos de vista de este modo:

TestA myView = new TestA(context); 
myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); 
setContentView(myView); 

problemas:

  1. El método de Testa onDraw(Canvas canvas) no es nunca llamado. He visto un par de soluciones a esto diciendo que mi vista no tiene ninguna dimensión (alto/ancho = 0), sin embargo, este no es el caso. Cuando anulo onLayout(), obtengo las dimensiones de mi diseño y son correctas. Además, getHeight()/Width() son exactamente como deberían ser. También puedo anular dispatchDraw() y obtener mis vistas base para dibujar.

  2. Quiero animar un objeto en TestB. Tradicionalmente, anularía el método onDraw() en la llamada invalidate() en sí mismo hasta que el objeto termine la animación que se suponía que debía hacer. Sin embargo, en TestB, cuando llamo al invalidate(), la vista nunca se vuelve a dibujar. Tengo la impresión de que el trabajo de mi padre es llamar al método onDraw() de nuevo, pero mi vista principal no vuelve a llamar al dispatchDraw().

supongo que mis preguntas son, ¿por qué mi método de mi vista padre onDraw() nunca llegan llamada para empezar? ¿Qué métodos en mi vista padre se supone que deben invocarse cuando uno de sus hijos se invalida? ¿Es el padre o la madre el responsable de garantizar que sus hijos se sienten atraídos o Android se ocupa de eso? Si Android responde al invalidate(), ¿por qué mi TestB nunca se vuelve a dibujar?

Respuesta

5

Bien, después de algunas investigaciones y muchas pruebas, descubrí que estaba haciendo tres cosas mal con respecto al problema # 2. Mucho de esto fue respuestas simples pero no muy obvias.

  • Necesita anular onMeasure() para cada vista. Dentro de onMeasure(), debe llamar al measure() para cada niño incluido en el ViewGroup pasando el MeasureSpec que el niño necesita.

  • Debe llamar al addView() para cada hijo que desea incluir. Originalmente, simplemente me crearon un objeto de vista y lo usé directamente.Esto me permitió dibujarlo una vez, pero la vista no se incluyó en el árbol de la vista, por lo que cuando llamé al invalidate() no estaba invalidando el árbol de vista y no redibujando. Por ejemplo:

En Testa:

TestB childView; 
TestA(Context context){ 
    ****** setup code ******* 
    LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
    childView = new TestB(context); 
    childView.setLayoutParams(params); 
} 

@Override 
protected void dispatchDraw(Canvas canvas){ 
    childView.draw(canvas); 
} 

Para ello se utilizará el punto de vista del niño una vez. Sin embargo, si esa vista necesita actualización para animaciones o lo que sea, eso fue todo. Puse addView(childView) en el constructor de TestA para agregarlo al árbol de la vista. código final es como tal:

TestB childView; 
TestA(Context context){ 
    ****** setup code ******* 
    LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
    childView = new TestB(context); 
    childView.setLayoutParams(params); 
    addView(childView); 
} 

@Override 
protected void dispatchDraw(Canvas canvas){ 
    childView.draw(canvas); 
} 

Alternativamente, podría anular dispatchDraw(Canvas canvas) al igual que si tuviera muchos más niños para dibujar, pero necesito un poco de elemento personalizado entre cada dibujo como líneas de cuadrícula o algo así.

@Override 
protectd void dispatchDraw(Canvas canvas){ 
    int childCount = getChildCount(); 
    for(int i = 0; i < size; i++) 
    { 
     drawCustomElement(); 
     getChildAt(i).draw(canvas); 
    } 
} 
  • debe invalidar onLayout() (se resumen en ViewGroup de todos modos, por lo que es necesario de todos modos). Dentro de este método, debe llamar al layout para cada niño. Incluso después de hacer las dos primeras cosas, mi punto de vista no invalidaría. Tan pronto como hice esto, todo funcionó perfectamente.

ACTUALIZACIÓN: 1 se ha resuelto Problema #. Otra solución extremadamente simple pero no tan obvia.

Cuando creo una instancia de TestA, tengo que llamar al setWillNotDraw(false) o Android no la dibujará por razones de optimización. Entonces la configuración completa es:

TestA myView = new TestA(context); 
myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); 
myView.setWillNotDraw(false); 
setContentView(myView); 
+0

puede compartir este proyecto de demostración del grupo de visualización en su blog o en algún lugar será de mucha ayuda .. Gracias amigo ... – user1201239

+0

¿necesito agregar el childView incluso si lo especificamos en XML? – user1201239

+0

Lo siento. No tengo un blog ni nada para subir. Trataré de ser tan útil como pueda. Para responder a tu primera pregunta, no. Cuando infle el xml, el elemento secundario está contenido en el 'ViewGroup'. Lo más temprano que puede recuperarlo es 'onFinishInflate()'. Después de eso tienes una opción. Obtenga sus hijos a través del método 'getChildAt (int index)' o use 'findViewById (int id)'. El índice será el orden en que los niños se encuentran en xml. Sin embargo, no sé cómo funciona la indexación con niños dentro de los niños. – DeeV

2

Esta no es una respuesta directa, pero here is a fantastic tutorial sobre cómo dibujar vistas personalizadas y ofrece un gran crash cours en cómo animar una vista. El código es muy simple y limpio también.

Espero que esto ayude!

+0

Gracias. Esto no solucionó mis problemas, pero me ayudó a llegar a la solución. – DeeV

Cuestiones relacionadas