Flutter Deep Dive, Parte 4: “RenderFlex children have non-zero flex…”

Argel Bejarano
Comunidad Flutter
Published in
12 min readMar 22, 2019

Esta es la ultima de las 4, recuerden que esta traducción se realizo lo más apegada posible para la comprensión de su versión original escrita por Scott Stoll.

Continuemos con la traducción parte cuatro! 😃

Este es la parte cuatro de la serie de 4. Puedes encontrar los otros aquí:

Antes de comenzar, es posible que desees tomar un momento para ir al baño y rellenar tu café, té, vodka o cualquier otra cosa que estés tomando. Es posible que también quieras tomar el medicamento para el dolor de cabeza que prefieras, ahora. Un gramo de prevención se supone que vale una tonelada métrica de cura o algo así….

¿Listos? Vayamos.

Hay seis pasos para presentar a los hijos de un Flex. Pegaré lo que dice la documentación sobre cada paso y luego haré lo mejor que pueda para traducir cada paso en humano:

Paso 1:

“Distribuya a cada niño un factor de flexibilidad nulo o nulo (por ejemplo, los que no son Expanded) con restricciones ilimitadas de los ejes principales y las restricciones de los ejes cruzados entrantes. Si la crossAxisAlignment es crossAxisAlignment.stretch, utilice en su lugar restricciones de ejes cruzados que coincidan con la extensión máxima de entrada en el eje cruzado.”

Primero, coloque a todos los hijos que no tienen ningún parámetro de flex o un flex parámetro que esté establecido en cero. Si el parámetro CrossAxisAlignment está configurado para estirarse, entonces haga que el hijo sea tan grande como su padre lo permita en el eje transversal.

Paso 2:

Divida el espacio del eje principal restante entre los hijos con factores de flexión distintos de cero (por ejemplo, los que son Expanded) de acuerdo con su factor de flexión. Por ejemplo, un hijo con un factor de flex de 2.0 recibirá el doble de espacio en el eje principal que un hijo con un factor de flex de 1.0.

En Humano: Divida el espacio sobrante a lo largo del eje principal entre todos los hijos que tienen una flex especificada y que la flex no es cero. Sin embargo, no todos los niños reciben el mismo trato. Tal vez te gustan más algunos hijos que otros, y quieres darles más espacio que otros.

So how do you do this? You determine who gets how much space by their flex. If you have 3 children and the flex of each is 1, 4, and 5; then here’s what happens:

  • La cantidad total de todos los flex es calculada. Aquí, 1 + 4 + 5 = 10, así tenemos un flex de 10 en total.
  • El primer hijo tiene un flex de 1 y el totale es 10, entonces el primer hijo toma 1/10 del resto del espacio sobrante reservado para el.

Ponga un pin en esa frase, “reservado para él”. Volveremos a buscarla más tarde.

  • El segundo hijo toma una reservación de 4/10 (40%) del total sobrante y el último nuestro favorito, toma 5/10 (mitad) reservado para su uso. of the total leftover space and the last one, your favorite, gets 5/10 (half)

Ahora calculamos el número real de dp que se reservará para cada uno, en función de cuál podría ser su parte del espacio sobrante.

No es. Puede ser.

Paso 3:

Distribuya cada uno de los hijos restantes con las mismas restricciones de los ejes transversales que en el paso 1, pero en lugar de utilizar las restricciones de los ejes principales ilimitadas, utilice las restricciones de los ejes máximos en función de la cantidad de espacio asignado en el paso 2". A los hijos con propiedades Flexible.fit se les imponen restricciones estrictas (es decir, se les obliga a llenar el espacio asignado), y a los hijos con propiedades Flexible.fit que están FlexFit.loose se les imponen restricciones flexibles (es decir, no se les obliga a llenar el espacio asignado)”

La primera cosa que un humano debe darse cuenta aquí es que no pusimos nada en el Paso 2; sólo hicimos un poco de matemáticas porque tenemos que saber exactamente cuántos dp (escritos como un double) cada uno de esos hijos va a tener reservado para que trabaje con ellos.

Cada hijo que tiene un flex entra en este proceso sin su eje principal de restricción establecido (el padre no ha puesto ningún límite a su tamaño todavía, por lo que sigue siendo “ilimitado”).

Así que el siguiente paso será hacer que las “restricciones del eje principal” máximo de cada niño sea el número máximo que se nos ocurrió en el Paso 2. Esto le permitirá estar a la altura de lo grande, pero nunca más grande que eso. Nunca olvides “nunca más grande que eso”. Se vuelve importante más adelante en este artículo e incluso más importante cada vez que se codifica una interfaz de usuario.

Pero espera, aún no hemos terminado. ¿Recuerdas esa caja de zapatos llamada fit? Es la mitad del problema cuando todo esto sale horriblemente mal. Si el FlexFit está suelto, básicamente significa que a nadie le importa. Sea tan grande como el hijo dice que quiere ser, como si ni siquiera tuviera unflex.

Oye, ¿Scott? Si a nadie le importa y el Flexible sólo va a hacer que el hijo tenga el mismo tamaño que iba a tener de todos modos, entonces, ¿por qué querría usar un ajuste suelto? ¿Por qué no usar al hijo sin envolverlo en un Flexible?

Hey, ¿lector? Esa es una muy buena pregunta, ¿y sabes qué? La única razón que se me ocurre es que es una de las dos cosas que necesitamos hacer si queremos arreglar nuestro error Boogeyman RenderFlex. Aparte de tratar con “RenderFlex, los hijos tienen una flexión distinta a cero, pero las restricciones de altura no tienen límites”, nadie con quien he hablado ha podido pensar en una sola razón para usar un ajuste suelto, nunca.

Volviendo a nuestro ejemplo…. Si el FlexFit está apretado, entonces el hijo intenta ocupar todo el espacio que le sobra. Recuerda, “apretado” significa empujar con fuerza contra cualquier límite que tus padres estén estableciendo. Una vez más, esto es lo que hace un Expanded, porque en realidad es un Flexible con su FlexFit hard-coded a tight.

Paso 4:

La extensión del eje transversal del Flex es la extensión máxima del eje transversal de los hijos (que siempre satisfará las restricciones entrantes).

Para averiguarlo se necesitaron tres diccionarios y una gitana llamada Wanda con una baraja de Tarot.

¿La versión simple? El tamaño del eje transversal de una Colum / Row va a ser tan grande como su hijo mayor en esa dirección. Si un hijo trata de ser más grande que eso, tira un error. Usualmente, esto será un desbordamiento que le mostrará las barras negras y amarillas, pero si anidó una Colum / Row dentro de otra Colum / Row, entonces podría ver a uno de los hermanos o hermanas de nuestro error Boogeyman:

“BoxConstraints forza una altura (o ancho) infinita”. (en el eje transversal)

Gracias Wanda.

Paso 6:

“Determine la posición para cada hijo de acuerdo con la alineación del eje principal y la crossAxisAlignment. Por ejemplo, si la mainAxisAlignment es mainAxisAlignment.spaceBetween, cualquier espacio del eje principal que no haya sido asignado a los hijos se dividirá de manera uniforme y se colocará entre los hijos.”

¿Has notado que todavía no hemos puesto nada en el Row oColumn? Hemos averiguado cuán grande se supone que debe ser cada niño tanto en el eje principal como en el eje transversal, y hemos averiguado cuán grande podría ser el Row oColumn. Pero todavía no hemos puesto a ningún hijo en él… y no podemos hacerlo todavía porque no tenemos ni idea del extremo de la Row oColumn por el que se supone que debemos empezar.

Ooops.

También vamos a necesitar saber si se supone que debemos agrupar a los niños, o separarlos y dejar espacio entre ellos.

Todas esas cosas están fuera del alcance de este artículo porque estamos aquí para tratar con esos mensajes de error y las cosas que los causan. No estamos cubriendo cada cosa sobre Rows yColumns. Dejaré que otro escriba ese Deep Dive.

En el código siguiente, ¿Cual es la altura de la Column?

Entonces, ¿qué te parece? 100 +10 = 110 y no hay flexión. El tamaño de mainAxisSize está configurado como mínimo, por lo que la Column no intentará llenar todo el espacio que le da su padre. Por lo tanto, la Column va a tener una altura de 110, ¿verdad?

Te equivocas.

Lee la letra pequeña

Repasemos:

  • Paso 1: “Diseña para cada niño un factor de flexibilidad nulo o nulo (por ejemplo, los que no son Expanded) con restricciones ilimitadas de los ejes principales y las restricciones de los ejes cruzados entrantes.”

Ambos hijos tienen una estatura fija y ninguno de ellos utiliza un factor de flexibilidad, por lo que se colocan inmediatamente. No hay otros hijos que colocar, y la estatura total de ambos es de 110.0

  • paso 5: “… Si la propiedad mainAxisSize es MainAxisSize.min, entonces la extensión del eje principal del Flex es la suma de las extensiones del eje principal de los hijos …”

¿Significa eso que la Column tiene que ser del tamaño de la suma de sus hijos? No, eso no es lo que dice. Pero, ¿te olvidaste de la segunda parte de “nunca olvides esto”?

“sujeto a las restricciones entrantes.”

Es como si necesitaras ser abogado para escribir una solicitud en estos días…. tienes que leer la letra pequeña, gente. Cuando se vuelve a poner todo junto, la parte del Paso 5 que tiene que ver con MainAxisSize.min es: “Si la propiedad mainAxisSize es MainAxisSize.min, entonces la extensión del eje principal del Flex es la suma de las extensiones del eje principal de los hijos (sujeto a las restricciones entrantes)”.

Lo que está pasando aquí es que las restricciones entrantes le están diciendo a MainAxisSize.min que se siente y se calle porque van a forzar a nuestra Column a ser tan grande como las restricciones máximas que el padre ha pasado. Así que aquí, el hecho de que mainAxisSize esté configurado en MainAxisSize.min no importa, porque las restricciones fueron pasadas.

Pero espera, el Container padre de nuestra Column no tenía un tamaño específico, así que ¿de dónde vinieron las restricciones?

Pasando Constraints al árbol

La respuesta, querido lector que ahora tiene dolor de cabeza, se encuentra en el código fuente para el Container:

container.dart line 171:

… El widget tiene un [hijo] pero no tiene`height`, ni `width`, ni [constraints], y ni [alignment], y el [Container] pasa el constraints desde el padre hasta el hijo y se ajusta al tamaño del hijo.

Claramente, esto es sólo una parte de un conjunto de comentarios mucho más amplio (e incluso más confuso), pero la parte que nos importa está en negrita. Nuestro contenedor padre “no tiene `height`, ni `width`, ni [constraints], and ni [alignment]”. Así que, en nuestro Container va a pasar las restricciones que le fueron dadas por su padre, y luego se dimensionará para que coincida con su hijo (nuestra Column).

Vamos a desglosarlo todo para que sea más fácil de ver:

  • Nuestro SizedBox tiene una altura de 500.
  • El primer hijo es el primer Container. No tiene altura específica y su padre SizedBox le esta pasando un constraint de 500 dp de alto. El Container le pasará estos 500 dp constraint de alto a nuestro Column.
  • El segundo hijo es nuestro Column, el cual necesita considerar a primero a su hijo antes de por calcular la altura. Tiene su mainAxisSize establecido como MainAxisSize.min, entonces este intentará reducirse hasta empatar el tamaño de cual sea el tamaño decida ser. Pero intentar hacer esto no es lo mismo que hacerlo!
  • Hijos 3 y 4 son Containers dentro del Column, con altura de 100 y 10, para un total de 110.
  • El Column dirá que sis hijos suman 110 y su mainAxisSize es al mínimo así que este quiere ser de 110…
  • Entonces el padre del Column dice, “Nope, estas sujeto a constrains de entrada que te he dado y este es el tamaño que seras. Ahora siéntate, callado y has lo que se te ha dicho
  • Entonces, el primer Container sera de 100, el segundo de 10 y entonces habrá 390 dp de espacio muerto dentro de nuestra Column.

Cuando miras a tu pantalla, parece que la Column es de 110 dp y que hay 390 dp de espacio muerto debajo de la Columna. Pero esos 390 dp de espacio muerto están dentro de la Column.

Y así es como un Containercon su mainAxisSizeconfigurado como mínimo y con un valor de 110 dp de hijos sigue siendo de 500 dp a pesar de que no hay flex en nada de esto.

¡Pero espera! ¡Hay más!

Ahora Alicia, asegúrate de que la cuerda de seguridad esté bien ajustada alrededor de la cintura porque a partir de aquí la madriguera del conejo empieza a ponerse verdaderamente rara….

¿Qué altura tiene la Column esta vez? ¿Qué tamaño va a tener el Container verde? ¿Qué tamaño va a tener el Container amarillo?

Pensando a fondo….

Por lo tanto, el Flexible con un ajuste apretado es realmente sólo un Expanded, así que eso es fácil. Y el Flexible con un ajuste suelto sólo ocupará 10, ya que un ajuste suelto significa que no tiene que ocupar todo el espacio que se le da.

El SizedBox va a pasar una restricción de 200 por el Container, así que sabemos que nuestra Column va a ser de 200 dp de alto porque lo aprendimos en el último Pop Quiz. Y si el Container amarillo toma 10, quedarán 190. Y todos sabemos que una Expandida es lo que usamos para ocupar cualquier espacio restante en una Column, así que la verde tiene que ser 190, ¿verdad?

Ni siquiera cerca.

Bienvenida al País de las Maravillas, Alicia. Las Leyes de la Física no se aplican aquí.

Detrás de la cortina de los magos

¿Recuerdas aquella vez, hace mucho, mucho tiempo en una parte de este artículo muy, muy lejos? Aquella vez que te hice clavar un pin en la frase “reservado para el” durante el Paso 2?

También te dije que nunca olvidaras algo en el Paso 3. ¿Lo olvidaste?

En el paso 2 dijimos:

“Podemos calcular el número actual de dp que seran reservados por cada uno, basado en las partes de espacio sobrante compartido podría ser.”

En el paso Step 3 dijimos:

“Esto permitirá ser grande, pero nunca mas grande que eso. Nunca olvides “nunca mas grande que eso”. ”

Lo que sucedío aquí fue esto:

  • Ambos Flexibles tienen una flex de 1, por lo que en el Paso 2 la cantidad de espacio que se reservó para cada uno fue la misma. Ambos tienen reservaciones para el 50% cada uno. Por lo tanto, se reservaron 100 dp para cada uno de ellos, y ahora cada uno de ellos nunca puede ser más grande que 100 dp.
  • El Container verde (en la parte superior) está rodeado de un Flexible que tiene un ajuste apretado, por lo que va a tomar hasta el último dp que pueda obtener (100).
  • El Container amarillo (en la parte inferior) está rodeado de un Flexible que tiene un ajuste suelto, por lo que no importa que se hayan reservado 100 dp para él. Sólo va a usar 10.

Resultado final:

  • El Column es 200 dp
  • El Container verde es 100 dp
  • El Container amarillo es 10 dp
  • Hay 90 dp de espacio muerto dentro el Column

So when people tell you to use an Expanded to eat up all of the leftover space in a Row / Column, you need to remember that if there is a loose fit Flexiblein there then you need to throw everything most people know about Rows, Columns and Expandeds… wait for it…

Así que cuando la gente te dice que uses un Expanded para comerte todo el espacio sobrante en una Rows/Columns, necesitas recordar que si hay un ajuste suelto Flexible ahí dentro entonces necesitas tirar todo lo que la mayoría de la gente sabe sobre Rows, Columns y Expandeds…. espera…

Justo el Hoyo del Conejo.

Y vivieron con una horrible migraña para siempre.

FIN

Puedes seguir al autor en Twitter en:

Y al traductor en:

--

--

Argel Bejarano
Comunidad Flutter

Flutter & Dart GDE | Speaker and Editor from Comunidad Flutter | Founder @EsFlutter