La première impression peut déterminer le succès ou l'échec d'une application mobile. Ainsi, vous devez vous assurer d'accompagner vos utilisateurs dès leur première ouverture de votre application. En présentant un tour guidé dès la complétion de l'inscription, l'application mobile Fizl est parvenue à accroître de 53 % le taux d'activation de ses nouveaux utilisateurs.
Dans cet article, nous vous expliquons étape par étape comment créer votre propre tour guidé en utilisant Expo, la plateforme de développement pour React Native. Pour faciliter votre implémentation, l'équipe chez Fizl met également à votre disposition une implémentation complète dans ce répertoire GitHub.
Avant de vous lancer, nous vous donnons notre meilleur conseil pour créer votre tour guidé :
Un tour guidé bien conçu n'est pas qu'un tutoriel; il construit une connexion émotionnelle avec vos utilisateurs pour encourager l'adoption et l'utilisation continue de votre application mobile.
Si vous avez besoin d'inspiration sur la manière de construire un tour guidé efficace, nous vous invitons à télécharger Fizl et expérimenter le tour guidé disponible pour nous utilisateurs.
Prérequis
Pour tirer le meilleur parti de cet article, vous devriez idéalement posséder ceci :
- Des connaissances de base avec les langages de programmation Javascript ou Typescript
- Des notions de base de la programmation avec des composants React Native ou React.
- Des connaissances de base de la plateforme de développement Expo.
Structure d'un tour guidé
Pour la création de notre tour guidé, nous implémenterons 3 types de composants : les Mask
, les Background
et les Card
.
Les composants Mask
Les Mask
, composés uniquement d'une View
, jouent 2 rôles importants : définir le contenu à mettre en évidence et permettre à l'utilisateur d'interagir avec ce contenu qui se trouve en arrière-plan. À titre d'exemple, vous retrouverez en encadrés rouges les deux Mask
implémentés dans le code à votre disposition.
1. Définir le contenu à mettre en évidence
Le contenu à mettre en évidence dépend entièrement de l'expérience que vous souhaitez offrir à vos utilisateurs grâce à votre tour guidé. Toutefois, nous avous encourageons à centraliser le style de votre contenu à mettre en évidence pour le réutiliser avec vos Mask
:
/** ../styles/masks.ts */
export const MASK1_BOTTOM = 70;
export const MASK1_RIGHT = 20;
export const MASK1_HEIGHT = 70;
export const masksStyles = StyleSheet.create({
mask1: {
backgroundColor: "green",
position: "absolute",
bottom: MASK1_BOTTOM,
right: MASK1_RIGHT,
width: MASK1_HEIGHT,
aspectRatio: 1,
borderRadius: 10,
},
// ...masks
});
Conseil : utilisez des variables globales pour positionner vos Mask
, car elles seront réutilisées pour les composants Card
et Background
.
2. Permettre les interactions avec le contenu en arrière-plan
En React Native, l'attribut pointerEvents="none"
appliqué à une View
indique que cette dernière doit ignorer les interactions tactiles. Nous utilisons cette technique pour permettre à l'utilisateur d'interagir avec le contenu en arrière-plan du Mask
.
/** ../components/Masks.tsx */
import { StyleProp, View, ViewStyle } from "react-native";
import { masksStyles } from "../styles/masks";
export function Mask1({ style }: { style?: StyleProp<ViewStyle> }) {
return <View style={[masksStyles.mask1, style]} pointerEvents="none" />;
}
Les composants Card
Les Card
sont beaucoup plus simples à implémenter et servent principalement à fournir du contenu informatif ainsi qu'à naviguer dans notre tour guidé. Le principal défi que vous pouvez rencontrer durant leur implémentation est le positionnement, qui doit être en position: "absolute"
. À titre d'exemple, vous retrouverez en encadrés rouges les deux Card
implémentées dans le code à votre disposition.
Rappel : en utilisant des variables globales pour positionner vos Mask
, vous pouvez facilement ajuster la position de vos Card
.
/** ../components/Cards.tsx */
const styles = StyleSheet.create({
card1: {
position: "absolute",
bottom: MASK1_BOTTOM + MASK1_HEIGHT + OFFSET,
alignSelf: "center",
},
// ...cards
});
Les composants Background
Les composants Background
ne sont pas obligatoires, mais ils empêchent l'utilisateur d'interagir avec le contenu qui n'est pas mis en évidence. Une technique simple utilisée chez Fizl consiste à recouvrir l'interface avec des composants TouchableOpacity
, à l'exception du composant Mask
, pour capturer les événements.
Il est également important d'ajouter l'attribut pointerEvents="box-none"
au composant View
parent pour permettre aux événements tactiles de passer à travers et d'atteindre ses composants enfants. Cela permettra à l'utilisateur d'interagir avec les TouchableOpacity
et le contenu en évidence derrière le Mask
.
/** ../components/Backgrounds.tsx */
export function Background2({ onPress }: { onPress: () => void }) {
return (
<View style={styles.layout} pointerEvents="box-none">
<TouchableOpacity
activeOpacity={1}
onPress={onPress}
style={{ height: MASK2_TOP }}
/>
<Mask2 style={{ position: "relative", opacity: 0 }} />
<TouchableOpacity
activeOpacity={1}
onPress={onPress}
style={{ flex: 1 }}
/>
</View>
);
}
const styles = StyleSheet.create({
layout: {
...StyleSheet.absoluteFillObject,
backgroundColor: "transparent",
},
});
Implémenter votre tour guidé
Une fois la structure de notre tour guidé en place, il ne nous reste plus qu'à centraliser nos composants dans une vue masquée.
Qu'est-ce qu'une vue masquée
Une vue masquée est un composant qui permet de contrôler l'affichage de son contenu en fonction du masque appliqué, à l'image d'un pochoir en forme d'étoile sur un dessin, qui ne laisse apparaître que sa forme sur la feuille. Nous utiliserons ce composant de la librairie externe @react-native-masked-view/masked-view
pour créer un effet visuel où les zones pertinentes de notre contenu sont mises en évidences par le biais des Mask
.
Il est déconseillé d'utiliser
@react-native-community/masked-view
, car elle est obsolète et incompatible avec React Navigation v6.
Centraliser nos composants
Rassembler les composants Mask
, Card
et Background
de votre tour guidé se fait en trois étapes :
1. Créer un layout
Le layout est une simple View
qui servira de conteneur pour vos Card
et votre MaskedView
. Pour atteindre le résultat visuel souhaité, vous devrez assigner un backgroundColor: "#000"
à ce composant parent.
/** ../App.tsx */
import RNMaskedView from "@react-native-masked-view/masked-view";
// ...imports
export default function App() {
// ...
return (
<View style={styles.layout}>
<MaskedView />
{index === 0 && <Card1 onNext={handleNext} />}
{index === 1 && <Card2 onNext={handleNext} />}
</View>
);
}
const styles = StyleSheet.create({
layout: {
flex: 1,
backgroundColor: "#000",
},
// ...styles
});
Remarque : pour permettre aux utilisateurs d'interagir avec les Card
, celles-ci doivent être ajoutées après votre composant MaskedView
.
2. Implémenter le MaskedView
Le composant RNMaskedView
de la librairie @react-native-masked-view/masked-view
accepte l'attribut maskElement
pour définir le Mask
appliqué aux composants enfants, y compris votre contenu et vos Background
. Le style backgroundColor: "#00000050"
appliqué à la View
contenant vos Mask
contrôle la visibilité de votre contenu en arrière-plan, où une augmentation de l'opacité rendra votre contenu plus visible.
/** ../App.tsx */
import RNMaskedView from "@react-native-masked-view/masked-view";
// ...imports
export default function App() {
// ...
function MaskedView() {
return (
<RNMaskedView
style={styles.container}
maskElement={
<View style={styles.masks}>
{index === 0 && <Mask1 />}
{index === 1 && <Mask2 />}
</View>
}
>
<Content />
{index === 0 && <Background1 onPress={onBackgroundPress} />}
{index === 1 && <Background2 onPress={onBackgroundPress} />}
</RNMaskedView>
);
}
// ...
}
const styles = StyleSheet.create({
// ...styles
container: {
backgroundColor: "#000000",
flex: 1,
},
masks: {
flex: 1,
backgroundColor: "#00000050",
width,
height,
},
});
3. Contrôler les interactions
À cette étape, vous devriez déjà être en mesure de visualiser votre travail. Pour contrôler les interactions de votre utilisateur avec votre tour guidé, il ne reste plus qu'à implémenter les fonctions onNext()
et onBackgroundPress()
. Cette première fonction, exécutée à partir de vos Card
, est essentielle pour actualiser index
, qui définit la progression de votre utilisateur dans votre tour guidé.
/** ../App.tsx */
export default function App() {
const [index, setIndex] = useState<number>(0);
function handleNext() {
setIndex(index + 1);
}
function onBackgroundPress() {
Alert.alert("Background pressed!");
}
// ...
}
Optimisations
De par leur implémentation, les MaskedView
sont des composants parents de votre contenu, ce qui peut entraîner des problèmes de performance pour les applications complexes. Voici deux stratégies utilisées chez Fizl pour pallier cette problématique.
1. Affichez le MaskedView uniquement lorsque nécessaire
Afin de minimiser l'impact sur la performance de votre application lorsque l'utilisateur ne suit pas votre tour guidé, nous vous recommandons de limiter l'affichage du MaskedView
uniquement au besoin. Voici un exemple simple pour atteindre cet objectif :
/** ../App.tsx */
export default function App() {
// ...
return shouldRenderGuidedTour ? (
<View style={styles.layout}>
<MaskedView />
{index === 0 && <Card1 onNext={handleNext} />}
{index === 1 && <Card2 onNext={handleNext} />}
</View>
) : (
<Content />
);
}
2. Limitez la portée de votre MaskedView
Si votre application implémente une navigation complexe avec @react-navigation/native-stack
et @react-navigation/bottom-tabs
, partager un même MaskedView
entre les pages de votre NativeStackNavigator
et de votre BottomTabNavigator
peut rapidement devenir un défi, sans parler des problèmes de performance significatifs au changement d'état d'une page dans votre NativeStackNavigator
. Nous vous recommandons de limiter la portée de votre MaskedView
et, si nécessaire, d'utiliser un useContext
pour suivre la progression de votre utilisateur dans les autres pages.
Conclusion
Un tour guidé offre une opportunité unique de faciliter l'intégration sur votre application mobile afin d'améliorer le taux d'activation de vos utilisateurs. Grâce au code mis à votre disposition sur ce répertoire GitHub, vous disposez de tous les outils nécessaires pour proposer une expérience utilisateur personnalisée dès l'ouverture de votre application mobile.