Créer des applications mobiles avec React Native

Auteur: Mohamed CHINY Durée necessaire pour le cours de Créer des applications mobiles avec React Native Niveau recommandé pour le cours de Créer des applications mobiles avec React Native Supports vidéo non disponibles pour ce cours Exercices de renforcement non disponibles pour ce cours Quiz non disponibles pour ce cours

Page 11: Styler une application React Native

Toutes les pages

Les styles en React Native

Styles inspirées du CSS et adaptés avec Javascript

En React Native, le style des composants s’inspire du CSS mais s’exprime en JavaScript via la prop style. On peut utiliser des styles inline, des objets créés avec StyleSheet.create, ou combiner plusieurs styles avec des tableaux.
On aura l'occasion de voir en détail la notion de prop plus loin dans ce cours. Pour le moment, dites vous qu'une prop est un peu comme un attribut que l'on applique à un composant.
Les propriétés des styles suivent le camelCase qui caractérise la syntaxe Javascript (par exemple: fontSize, backgroundColor...). Les valeurs exprimées avec des unités en CSS comme border-width:1px sont unitless en React Native. C'est à dire que les valeurs de ces propriétés-là sont exprimées sans unité comme borderWidth:1 .

Pour des interfaces plus modulaires et dynamiques, on peut intégrer des bibliothèques comme styled-components, NativeWind ou react-native-paper, qui facilitent la thématisation et la réutilisation. Le styling en React Native est donc à la fois souple, performant et adapté aux contraintes mobiles.

Comment React Native traite-t-il les valeurs qui décrivent des dimensions?

On sait que React Native est unitless, ce qui signifie que les valeurs de propriétés qui décrivent des dimensions sont exprimées sous forme numérique sans unité. Cependant, certaines propriétés peuvent admettre plusieurs types d'unités comme px, pt, em... Donc, comment React Native décide-t-il de l'unité à appliquer?

En React Native, les dimensions des composants (telles que width, height, margin, padding, borderWidth ou fontSize) sont exprimées en unités abstraites sans suffixe, interprétées comme des pixels indépendants de la densité. Sur Android, ces valeurs correspondent à des scale-independent pixels (sp) pour le texte, ce qui permet de respecter les préférences d’accessibilité de l’utilisateur. Sur iOS, elles sont traduites en points typographiques (pt). Cette abstraction permet à React Native d’unifier le rendu visuel entre plateformes en garantissant une apparence cohérente quel que soit l’écran ou la densité.
Si vous voulez en savoir davantage, je vous suggère ce lien sur le site officiel de React Native qui décrit la manière dont les valeurs des propriétés width et height sont calculées. Dans tous les cas, si vous n'avez pas bien compris la théorie derrière le calcul des dimensions, ce n'est pas grave. Avec les exemples et la pratique vous saurez maitriser l'apparence des composants.

Appliquer les styles au composants

Flexbox - Disposition des layouts par défaut en React Native

React Native repose entièrement sur Flexbox pour gérer la disposition des éléments à l’écran. Chaque composant, comme View ou Text, est positionné selon un système de boîtes flexibles. Par défaut, les éléments sont organisés en colonne (flexDirection: 'column'), mais on peut facilement les aligner horizontalement (row), répartir l’espace (justifyContent), ou gérer l’alignement vertical (alignItems). Ce système permet de créer des interfaces adaptables à toutes les tailles d’écran, avec une logique unifiée entre Android et iOS.
Maîtriser Flexbox est essentiel pour structurer efficacement les layouts en React Native. Je vous renvoie vers mon cours sur les boites flexibles (Flexbox) en CSS pour en apprendre davantage.

Inline style

Le inline style en React Native désigne l’application directe de styles à un composant via la prop style sous forme d’un objet JavaScript. C’est l’équivalent de l’attribut style en HTML, mais adapté à la syntaxe JavaScript.

Exemple:
import { View, Text } from 'react-native';

export default function App() {
   return (
      <View style={
         {flex: 1,
         alignItems:"center",
         justifyContent:"center"}
      }>
         <Text style={
            {fontSize:20,
            color:"#0000FF"}
         }>Bonjour</Text>
      </View>
   );
}
Pour appliquer l'inline style, on invoque un objet Javascript en se servant de l'interpolation JSX. Par défaut, le style flex est appliqué au core component View avec une disposition en colonne, mais il faut préciser l'alignement de l'axe principale et l'axe secondaire. C'est pour cela qu'on a précisé alignItems et justifyContent. Si on oubliait de les spécifier, le contenu (les éléments imbriqués dans le composant View) serait placé en haut de l'écran.

Concernant le composant Text, nous avons spécifié le style fontSize (taille du texte) avec la valeur 20 (unitless) et une couleur bleue.

Après exécution, on aura un résultat qui ressemble à ceci:
Bonjour

Méthode StyleSheet.create

La méthode StyleSheet.create (de l'objet natif StyleSheet) est une méthode fournie par React Native pour définir et organiser les styles de manière optimisée. Plutôt que d’écrire des styles inline, on regroupe les styles dans un objet dédié, ce qui améliore la lisibilité, la réutilisabilité et les performances.

Appliquons les même styles de l'exemple précédent, mais cette fois à l'aide de la méthode StyleSheet.create:
import { StyleSheet, View, Text } from 'react-native';

export default function App() {
   return (
       <View style={styles.container}>
           <Text style={styles.text}>Bonjour</Text>
       </View>
   );
}

const styles = StyleSheet.create({
   container: {
       flex: 1,
       alignItems: 'center',
       justifyContent: 'center',
   },
   text:{
       color:"#0000FF",
       fontSize:20
   }
});
La méthode StyleSheet.create() se place en dehors du composant React juste après les imports et avant ou après la déclaration du composant, selon notre préférence de structure. Mais on préfère généralement l'insérer après la déclaration du composant.

Il ne faut pas oublier d'importer le module StyleSheet (au côté d'autres composants requis) depuis la librairie react-native:
import { StyleSheet, View, Text } from 'react-native';
La méthode StyleSheet.create() contient un objet JavaScript qui définit un ensemble de styles nommés, chacun étant lui-même un objet de propriétés de style. La méthode StyleSheet.create retourne un objet (que nous avons appelé styles dans cet exemple).

Il suffit ensuite d'invoquer le style au sein du composant voulu à l'aide la prop style:
<View style={styles.container}>
   <Text style={styles.text}>Bonjour</Text>
</View>

Tableaux de styles

Les tableaux de styles en React Native permettent de combiner plusieurs styles dans une seule prop style. C’est une fonctionnalité puissante et souple, très utile pour appliquer des styles conditionnels ou superposés.

Exemple:
import { StyleSheet, View, Text } from 'react-native';

export default function App() {
   return (
       <View style={styles.container}>
           <Text style={[styles.text, styles.text2]}>
               Bonjour
           </Text>
       </View>
   );
}

const styles = StyleSheet.create({
   container: {
       flex: 1,
       alignItems: 'center',
       justifyContent: 'center',
   },
   text:{
       color:"#0000FF",
       fontSize:20
   },
   text2:{
       borderWidth:1,
       fontFamily:"sans-serif"
   }
});
Dans ce cas, nous avons appliqué à la fois les styles text et text2 sur le composant Text. Ce qui donne ce résultat:
Bonjour

Il est toutefois possible d'appliquer des styles conditionnels, c'est à dire des styles qui s'appliquent au composants une fois une condition réalisée. Ce qui est un peu similaire aux pseudo-classes en CSS.
La notions de pseudo-classes que l'on trouve en CSS est absente en React Native. Or, on peut les simuler avec des states comme on le fera dans l'exemple qui va suivre.
Imaginons que l'on souhaite intégrer un bouton en dessous de notre texte. On imagine qu'initialement le texte n'a pas de bordure (style text2 non appliqué). Par contre, une fois on clique sur le bouton, la bordure apparaitra.

Je propose le code suivante:
import { useState } from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';

export default function App() {
   const [color,setColor]=useState(false)
   const handleColor=()=>{
       setColor(true)
   }
   return (
       <View style={styles.container}>
           <Text style={
               [styles.text, color && styles.text2]
           }>
               Bonjour
           </Text>
           <Button title="Changer de couleur"
           onPress={handleColor} />
       </View>
   );
}

const styles = StyleSheet.create({
   container: {
       flex: 1,
       backgroundColor: '#fff',
       alignItems: 'center',
       justifyContent: 'center',
   },
   text:{
       color:"#0000FF",
       fontSize:20
   },
   text2:{
       borderWidth:1,
       fontFamily:"sans-serif"
   }
});
Dans ce cas, nous avons spécifié une condition avant d'appliquer le style text2 comme ceci:
[styles.text, color && styles.text2]
Le state color est initialisé à false. Quand on presse le bouton, il passe à true. C'est à ce moment là que le style text2 est appliqué.
Ce genre d'écriture conditionnelle color && styles.text2 est très courante en React et React Native. On l'applique souvent à des composants afin de décider si on doit les afficher ou non. Nous aurons l'occasion de traiter l'affichage conditionnel et itératif en React Native plus loin dans ce cours.