• 30 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 09/09/2020

Construisez vos vues avec Flexbox

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

J'ai laissé ce sujet de côté dans le chapitre précédent. Pardonnez-moi, mais j'avais besoin de vous présenter les styles avant de vous parler de Flexbox. Cette fois, on y est ! :pirate:

Mais qu'est-ce que Flexbox, au juste ? Et pourquoi ce terme revient à chaque fois que l'on parle de style ?

Première chose, Flexbox n'a rien à voir avec React et React Native. Cela existait bien avant, ce n'est donc pas une création made in Facebook. C'est un mode de mise en page, utilisé sur du web à la base, permettant de gérer les tailles et les positions de vos éléments dynamiquement. Avec Flexbox, on pense et on construit nos vues comme des boîtes flexibles (wouah merci pour la traduction :p) qui s'ajustent entre elles.

Flexbox et React Native

En React Native, tous les components utilisent Flexbox et sont des "boîtes flexibles". Donc, dès lors que vous appliquez un style de margin, un padding, un alignement, une taille dynamique, bref tout ce qui touche à du positionnement d'éléments, vous passez sans trop le savoir par Flexbox. C'est pour cela que bon nombre de styles sont regroupés dans la partie "Flexbox" de la documentation des styles que j'ai partagée avec vous dans le chapitre précédent.

C'est bien tout ça, mais pourquoi aurais-je besoin de gérer les dimensions et les positionnements de mes éléments de manière dynamique et avec Flexbox ?

Tout simplement parce que la principale difficulté du développement d'application mobile est d'adapter ses vues aux différentes tailles d'écran. 

Prenons l'exemple où vous souhaitez couper une vue en deux parties égales. Si vous utilisez des dimensions statiques, vous allez créer un component avec un  render  équivalent à :

render() {
return (
<View style={{ backgroundColor: 'yellow' }}>
<View style={{ height: 335, backgroundColor: 'red' }}></View>
<View style={{ height: 335, backgroundColor: 'green' }}></View>
</View>
)
}

Et regardez si j'affiche ce component sur un iPhone 6 et un iPhone 7 Plus, deux smartphones avec des tailles d'écran différentes :

Définition d'une hauteur statique sur deux vues affichées sur deux écrans différentes
Définition d'une hauteur statique sur deux vues affichées sur deux écrans différents

Vous voyez le problème ? :) Sur l'iPhone 6, ça va ; sur le 7 Plus, ça ne va plus. Et là encore, j'ai pris l'exemple d'iOS qui possède moins de 10 tailles d'écran différentes (iPhone / iPad inclus). Sur Android, c'est l'anarchie totale ! Il y a des milliers de tailles d'écran différentes et, en utilisant des tailles statiques, votre application ne va s'afficher correctement que chez quelques utilisateurs seulement.

Flexbox, à toi de jouer

C'est ici que Flexbox entre en jeu. Au lieu de définir des tailles statiques, nous allons couper notre vue en plusieurs blocs et indiquer quelle part de l'écran nos blocs vont prendre. Pour ce faire, nous allons utiliser le style  flex  de Flexbox.

Style flex

Si je reprends l'exemple précédent, nos vues rouge et verte doivent prendre la même part d'écran, pour faire moitié-moitié. Avec Flexbox et le style  flex, on va faire :

render() {
return (
<View style={{ flex: 1, backgroundColor: 'yellow' }}>
<View style={{ flex: 1, backgroundColor: 'red' }}></View>
<View style={{ flex: 1, backgroundColor: 'green' }}></View>
</View>
)
}

Qu'a-t-on fait ici ? On dit à la vue rouge de prendre une part (  flex  = 1) et à la vue verte de prendre une part également (  flex  = 1). Étant donné qu'elles possèdent des parts égales, elles vont se partager l'écran.

On obtient :

Définition d'une hauteur statique sur deux vues affichées sur deux écrans différentes
Définition d'une hauteur dynamique avec Flexbox sur deux vues affichées sur deux écrans différents

Ça marche, super !

Bon, j'avoue que je suis allé un peu vite, là. :p Vous devez être en train de vous demander pourquoi on applique le style  flex  à 1 sur toutes nos vues, y compris la première (celle avec le background jaune).

Par défaut, TOUS les components React Native ont un style  flex  à 0. Lorsqu'un component a un style  flex  à 0, il adapte sa taille en fonction de son style  height  et, s'il n'a pas de style  height  , il adapte sa taille en fonction de celle de ses components enfants.

Je m'explique. Dans le premier exemple, on a fait :

render() {
return (
<View style={{ backgroundColor: 'yellow' }}>
<View style={{ height: 335, backgroundColor: 'red' }}></View>
<View style={{ height: 335, backgroundColor: 'green' }}></View>
</View>
)
}

On n'a pas défini de style  flexflex  vaut donc 0 sur toutes nos vues. On n'a pas défini de  height  sur notre vue globale, la jaune. De ce fait, sa taille dépend entièrement de ses components enfants : les vues rouge et verte. Ces deux components enfants ont chacun une hauteur de 335. Si on n'est pas trop mauvais en math, on peut en déduire que notre vue globale a une hauteur de 770, et c'est le cas. Pour le prouver, on va enlever le  backgroundColor  dans notre vue verte : 

render() {
return (
<View style={{ backgroundColor: 'yellow' }}>
<View style={{ height: 335, backgroundColor: 'red' }}></View>
<View style={{ height: 335 }}></View>
</View>
)
}

Ce qui nous donne, sur un iPhone 7 Plus :

Vue jaune sans style flex ni height, dépendant entièrement de la taille de ses components enfants
Vue jaune sans style flex ni height, dépendant entièrement de la taille de ses components enfants

Vous commencez à mieux comprendre ? ;) Notre vue globale jaune ne prend pas tout l'écran actuellement !

À présent, si on définit un style  flex  à 1 pour une vue, qu'est-ce que cela change ?

Et bien, c'est tout le contraire. Au lieu de lui dire "adapte ta taille en fonction de tes components enfants" (comme c'est le cas avec un style  flex  à 0 par défaut), on lui dit "prends toute la place disponible offerte par ton component parent et, s'il y a plusieurs components adjacents, partage la place disponible avec eux".

Reprenons notre exemple avec des dimensions dynamiques avec Flexbox :

render() {
return (
<View style={{ flex: 1, backgroundColor: 'yellow' }}>
<View style={{ flex: 1, backgroundColor: 'red' }}></View>
<View style={{ flex: 1, backgroundColor: 'green' }}></View>
</View>
)
}

On dit à notre vue jaune de prendre toute la place disponible (  flex  = 1). Elle n'a pas de components adjacents et son component parent, c'est votre écran. Elle va donc prendre toute la taille de l'écran.

Ensuite, on dit à la vue rouge de prendre toute la place disponible. Elle a un component adjacent (la vue verte), donc elle va partager la place disponible avec elle. Voilà comment le style  flex  fonctionne.

Si on ne met pas de style  flex  à 1 sur la vue globale jaune, que se passe-t-il ?

En gros, si on a ceci :

render() {
return (
<View style={{ backgroundColor: 'yellow' }}>
<View style={{ flex: 1, backgroundColor: 'red' }}></View>
<View style={{ flex: 1, backgroundColor: 'green' }}></View>
</View>
)
}

Essayez de réfléchir par vous-même sur le résultat de ce code avant de le tester, c'est une bonne manière pour apprendre.

Votre vue jaune a un style  flex  à 0 (valeur par défaut), elle n'a pas de style  height  non plus ; sa taille dépend donc de celle de ses components enfants. Seulement, ici, ses components enfants (vues rouge et verte) se basent sur la place disponible offerte par le component parent, la vue jaune. C'est le serpent qui se mord la queue. o_O Ici, chacun de vos components base sa taille sur celle des autres, sans que personne ne tranche en disant : "Voici ma taille, basez-vous là-dessus." Finalement, votre application ne va rien afficher : écran blanc.

Voilà pourquoi on définit un style  flex  à 1 sur notre vue globale jaune. Lorsque les components enfants (vues rouge et verte) vont demander la place disponible, la vue globale jaune répondra : "Ma taille correspond à tout l'écran, servez-vous !"

En pratique, dès lors que l'on crée une nouvelle vue, on lui applique tout de suite un style  flex  à 1 afin de s'assurer qu'elle occupe tout l'écran. C'est ce que l'on va faire immédiatement sur la vue globale de notre component Search. On va en profiter également pour externaliser ce style :

render() {
return (
<View style={styles.main_container}>
<TextInput style={styles.textinput} placeholder='Titre du film'/>
<Button title='Rechercher' onPress={() => {}}/>
</View>
)
}
const styles = StyleSheet.create({
main_container: {
flex: 1,
marginTop: 20
},
textinput: {
...
}
})

Jouez sur les parts occupées par nos components

Ici, on a défini des parts égales à nos deux vues, flex  à 1 pour les vues rouge et verte. De ce fait, vous devez penser que le style  flex  ne prend que deux valeurs possibles : 0 et 1. Pas du tout, on peut mettre la valeur que l'on souhaite ici. Et c'est justement cette valeur qui va nous permettre d'ajuster les parts occupées par nos components. Prenons l'exemple de ce code :

render() {
return (
<View style={{ flex: 1, backgroundColor: 'yellow' }}>
<View style={{ flex: 1, backgroundColor: 'red' }}></View>
<View style={{ flex: 2, backgroundColor: 'green' }}></View>
<View style={{ flex: 3, backgroundColor: 'blue' }}></View>
</View>
)
}

Ici, on a 3 components enfants à la vue jaune et on dit à ces components de se partager l'écran. Seulement, ici, la vue bleue doit prendre 3 fois plus d'espace que la vue rouge, la vue verte deux fois plus d'espace que la vue rouge et la vue bleue 1,5 (3/2) fois plus d'espace que la vue verte. Dit comme cela, c'est un peu barbant, alors utilisons un peu de math (vraiment un tout petit peu :honte:). Ici, on découpe notre espace en 6 (1 + 2 + 3) et on dit :

  • vue rouge prend 1/6 de l'écran ;

  • vue verte prend 1/3 (2/6) de l'écran ;

  • vue bleue prend 1/2 (3/6) de l'écran.

On vérifie à l'écran :

Modifier les parts de chaque vue avec Flex
Modifier les parts de chaque vue avec Flex

C'est aussi simple que cela de modifier les parts occupées par chacun de nos components.

Bien sûr, on ne va pas toujours utiliser le style  flex  sur nos components. Souvent, on a besoin de mixer les dimensions statiques et dynamiques. Par exemple, un bouton est souvent défini avec une valeur statique pour qu'il occupe la même taille sur tous les écrans (exemple :  height: 50 ), contrairement à une vue avec une liste de films où on définit une valeur dynamique pour qu'elle occupe la place disponible et la même part sur tous les écrans (exemple :  flex: 1 ).

Depuis le début de ce chapitre et même de ce cours, tous les components se mettent à la suite les uns des autres, et ce, verticalement. Rien n'est magique avec React Native. :magicien:

Aligner ses éléments

Même si on passe sur une autre sous-partie du chapitre, je vous en ai parlé, les alignements d'éléments passent eux aussi par Flexbox.

Style FlexDirection

Par défaut, les components possèdent un style flexDirection: 'column' qui aligne verticalement les components entre eux. Si vous souhaitez modifier la direction de l'alignement entre des components, il faut modifier le style flexDirection  du component parent. C'est lui qui va dire à ses components enfants comment s'aligner. Le style  flexDirection  a deux valeurs possibles :

  • column  : alignement vertical.

  • row  : alignement horizontal.

Si on reprend notre dernier exemple et que l'on change le style  flexDirection  par défaut :

render() {
return (
<View style={{ flex: 1, flexDirection: 'row', backgroundColor: 'yellow' }}>
<View style={{ flex: 1, backgroundColor: 'red' }}></View>
<View style={{ flex: 2, backgroundColor: 'green' }}></View>
<View style={{ flex: 3, backgroundColor: 'blue' }}></View>
</View>
)
}

On obtient :

Alignement horizontal de components
Alignement horizontal de components

Style JustifyContent

Le style  justifyContent  permet de définir comment sont distribués vos components enfants sur l'axe principal. Normalement, j'ai perdu tout le monde avec cette phrase. :lol:

Première chose, l'axe principal dépend de l'alignement choisi avec le style  flexDirection  :

  • Si vous avez un style  flexDirection: 'column' , l'alignement est vertical et l'axe principal est Y. L'axe secondaire est X.

  • Si vous avez un style  flexDirection: 'row' , l'alignement est horizontal et l'axe principal est X. L'axe secondaire est Y.

Seconde chose, on peut définir comment sont positionnés les éléments enfants entre eux : s'ils s'alignent tous au début, tous à la fin, s'ils se centrent, etc.

On va prendre un nouvel exemple avec 3 components enfants de dimension 50x50 :

render() {
return (
<View style={{ flex: 1, backgroundColor: 'yellow' }}>
<View style={{ height: 50, width: 50, backgroundColor: 'red' }}></View>
<View style={{ height: 50, width: 50, backgroundColor: 'green' }}></View>
<View style={{ height: 50, width: 50, backgroundColor: 'blue' }}></View>
</View>
)
}

Par défaut, l'alignement est vertical, l'axe principal est donc Y et l'axe secondaire X. Cela nous donne à l'écran :

Alignement par défaut de 3 components 50x50
Alignement par défaut de 3 components 50x50

 On va définir une valeur pour le style  justifyContent  et donc jouer sur l'axe principal (Y ici) : 

render() {
return (
<View style={{ flex: 1, justifyContent: 'center', backgroundColor: 'yellow' }}>
<View style={{ height: 50, width: 50, backgroundColor: 'red' }}></View>
<View style={{ height: 50, width: 50, backgroundColor: 'green' }}></View>
<View style={{ height: 50, width: 50, backgroundColor: 'blue' }}></View>
</View>
)
}

La valeur  center  va centrer nos components enfants sur l'axe principal Y : 

Style justifyContent : center sur l'axe Y
Style justifyContent : center sur l'axe Y

Et voilà ! :soleil: Il existe 6 valeurs possibles pour le style  justifyContent  :  

center

Aligner les éléments au centre

flex-start

Aligner les éléments au début

flex-end

Aligner les éléments à la fin

space-between

Les éléments s'affichent sur tout l'axe et laissent de l'espace entre eux.

space-around

Pareil que  space-between , sauf qu'ici, il y a de l'espace entre eux et entre les extrémités de la vue. L'espace aux extrémités est 2 fois inférieur à l'espace entre les éléments.

space-evenly

Petit dernier arrivé récemment. Pareil que  space-around , à la différence que l'espace aux extrémités est le même que celui entre les éléments.

Je vous invite vraiment à jouer avec ces propriétés pour vous rendre compte de l'effet de chacune.

On a parlé de l'axe principal, il est temps de passer à l'axe secondaire. :pirate:

Style AlignItems

Le style  alignItems  est comme  justifyContent, sauf qu'il s'applique sur l'axe secondaire.

Si je reprends notre exemple précédent, en remplaçant juste le style  justifyContent  par  alignItems  pour centrer les éléments sur l'axe secondaire (X ici) :

render() {
return (
<View style={{ flex: 1, alignItems: 'center', backgroundColor: 'yellow' }}>
<View style={{ height: 50, width: 50, backgroundColor: 'red' }}></View>
<View style={{ height: 50, width: 50, backgroundColor: 'green' }}></View>
<View style={{ height: 50, width: 50, backgroundColor: 'blue' }}></View>
</View>
)
}

On aura :

Style alignItems : center sur l'axe X
Style alignItems : center sur l'axe X

Il existe 4 valeurs possibles pour le style  alignItems  :

center

Aligner les éléments au centre 

flex-start

Aligner les éléments au début

flex-end

Aligner les éléments à la fin

stretch

Les éléments s'étirent sur tout l'axe. Attention, cette propriété fonctionne uniquement si vous ne définissez pas de dimension statique sur l'axe secondaire. Ici, il ne faut pas définir de width sur les components enfants.

Et que se passe-t-il, si on mixe un peu tout ?

render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'yellow' }}>
<View style={{ height: 50, width: 50, backgroundColor: 'red' }}></View>
<View style={{ height: 50, width: 50, backgroundColor: 'green' }}></View>
<View style={{ height: 50, width: 50, backgroundColor: 'blue' }}></View>
</View>
)
}

Résultat :

Style justifyContent : center sur l'axe Y et alignItems : center sur l'axe X
Style justifyContent : center sur l'axe Y - alignItems : center sur l'axe X

C'est sympa et plutôt simple, non ?

On arrive au terme de ce chapitre plutôt conséquent, je m'en excuse, mais je voulais vous présenter toutes les fonctionnalités liées à Flexbox. On en aura besoin pour nous lancer plus loin dans les développements.

Pour certains, Flexbox est une découverte, pour d'autres, issus du développement web, c'était peut-être un rappel. Dans tous les cas, retenez bien que votre application n'est qu'une suite de boîtes flexibles, encapsulées les unes avec les autres, où vous vous contentez d'ajuster les tailles et les espaces entre chacune d'elles.

On en a terminé avec les styles, en tout cas avec leur présentation. On va mettre en pratique tout ce que l'on a vu par la suite, en réalisant notre application.

D'ailleurs, en parlant de notre application pour gérer nos films, on n'a pas vraiment avancé, c'est ma faute. :-° Mais maintenant que vous avez toutes les clés en main, Components et Styles, on va pouvoir enclencher la seconde.

Exemple de certificat de réussite
Exemple de certificat de réussite