Code my UI – React Native

Code my UI with React native

Oy oy !

Petit challenge de code en ce début d’année avec ma technologie préférée du moment : React Native.

En ce début d’année je suis tombé sur ce super prototype d’écran et j’ai eu envie d’en faire une version avec React Native.

Dans cet article je vais essayer de me rapprocher le plus possible de cet écran et de vous montrer la facilité du développement. Let’s go !

 

Let’s Code !

Je commence donc par initialiser le projet :

[pastacode lang= »bash » manual= »react-native%20init%20codemyui » message= » » highlight= » » provider= »manual »/]

Ensuite dans le package.json j’ajoute les dépendances dont j’ai besoin :

[pastacode lang= »javascript » manual= »%22dependencies%22%3A%20%7B%0A%09%09%22react%22%3A%20%2215.4.2%22%2C%0A%09%09%22react-native%22%3A%20%22%5E0.40.0%22%2C%0A%09%09%22react-native-linear-gradient%22%3A%20%22%5E1.5.15%22%2C%0A%09%09%22react-native-vector-icons%22%3A%20%22%5E2.0.2%22%0A%09%7D%2C » message= » » highlight= » » provider= »manual »/]

react-native-linear-gradient va me fournir le moyen rapide de faire mes dégradés tandis que react-native-vector-icons me fourni des font icons.

Une fois mon répertoire de travail créé je commence avec la structure de ma page :

[pastacode lang= »javascript » manual= »import%20React%2C%20%7BComponent%7D%20from%20’react’%3B%0Aimport%20%7BView%2C%20Text%2C%20StyleSheet%7D%20from%20’react-native’%3B%0A%0A%2F%2F%20Styles%0Aconst%20styles%20%3D%20StyleSheet.create(%7B%0A%0A%7D)%3B%0A%0Aexport%20default%20class%20BookAFlight%20extends%20Component%20%7B%0A%20%20%20%20render()%20%7B%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CHeader%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%2F*%20Will%20contains%20flight%20search%20information%20*%2F%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FHeader%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CFlightList%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%2F*%20Will%20contains%20flight%20results%20*%2F%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FFlightList%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CProceedAction%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%2F*%20Will%20contains%20proceed%20button%20*%2F%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FProceedAction%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%7D%0A%7D%0A » message= » » highlight= » » provider= »manual »/]

Je passe ensuite aux composants.

Composants

<Header>

Le mockup nous présente plusieurs informations à afficher :

  • Ville et aéroport de départ
  • Ville et aéroport d’arrivée

J’utilise flexbox pour aligner mes éléments. Le dégradé et l’image sont placés de façon « absolute » dans la page.

Le code (avec les valeurs en dur) :

[pastacode lang= »javascript » manual= »import%20React%2C%20%7BComponent%7D%20from%20’react’%3B%0Aimport%20%7BView%2C%20Text%2C%20StyleSheet%2C%20Dimensions%2C%20Image%7D%20from%20’react-native’%3B%0Aimport%20LinearGradient%20from%20’react-native-linear-gradient’%3B%0Avar%20FontAwesome%20%3D%20require(‘react-native-vector-icons%2FFontAwesome’)%3B%0A%0A%2F%2F%20App%0Aimport%20Row%20from%20′.%2FRow’%3B%0A%0A%2F%2F%20Styles%0Aconst%20%7Bwidth%7D%20%3D%20Dimensions.get(‘window’)%3B%0Aconst%20headerHeight%20%3D%20150%3B%0Aconst%20styles%20%3D%20StyleSheet.create(%7B%0A%20%20%20%20container%3A%20%7B%0A%20%20%20%20%20%20height%3A%20headerHeight%2C%0A%20%20%20%20%7D%2C%0A%20%20%20%20info%3A%20%7B%0A%20%20%20%20%20%20%20%20paddingHorizontal%3A%2040%0A%20%20%20%20%7D%2C%0A%20%20%20%20gradient%3A%20%7B%0A%20%20%20%20%20%20%20%20position%3A%20’absolute’%2C%0A%20%20%20%20%20%20%20%20top%3A%20-18%2C%0A%20%20%20%20%20%20%20%20width%2C%0A%20%20%20%20%20%20%20%20height%3A%20headerHeight%20%2B%2018%2C%0A%20%20%20%20%20%20%20%20paddingTop%3A%2040%0A%20%20%20%20%7D%2C%0A%20%20%20%20text%3A%20%7B%0A%20%20%20%20%20%20%20%20backgroundColor%3A%20’transparent’%2C%0A%20%20%20%20%20%20%20%20color%3A%20’white’%0A%20%20%20%20%7D%2C%0A%20%20%20%20labelFromTo%3A%20%7B%0A%20%20%20%20%20%20%20%20fontSize%3A%2015%2C%0A%20%20%20%20%20%20%20%20fontWeight%3A%20’100’%0A%20%20%20%20%7D%2C%0A%20%20%20%20textFromTo%3A%20%7B%0A%20%20%20%20%20%20%20%20fontSize%3A%2024%2C%0A%20%20%20%20%20%20%20%20fontWeight%3A%20’bold’%0A%20%20%20%20%7D%2C%0A%20%20%20%20image%3A%20%7B%0A%20%20%20%20%20%20%20%20position%3A%20’absolute’%2C%0A%20%20%20%20%20%20%20%20top%3A%20-18%2C%0A%20%20%20%20%20%20%20%20height%3A%20headerHeight%20%2B%2018%0A%20%20%20%20%7D%0A%7D)%3B%0A%0Aexport%20default%20class%20Header%20extends%20Component%20%7B%0A%20%20%20%20render()%20%7B%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7Bstyles.container%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CImage%20source%3D%7B%7Buri%3A%20’seattle’%2C%20isStatic%3A%20true%2C%20width%2C%20height%3A%20headerHeight%7D%7D%20style%3D%7Bstyles.image%7D%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CLinearGradient%20colors%3D%7B%5B’%232196F3CC’%2C%20’%23EC6EADCC’%5D%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20style%3D%7Bstyles.gradient%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20start%3D%7B%7Bx%3A%200.0%2C%20y%3A%200.25%7D%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20end%3D%7B%7Bx%3A%201%2C%20y%3A%20.45%7D%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7Bstyles.info%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CRow%20justifyContent%3D%22space-between%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5Bstyles.text%5D%7D%3EFLYING%20FROM%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5Bstyles.text%5D%7D%3EFLYING%20TO%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FRow%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CRow%20justifyContent%3D%22space-between%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5Bstyles.text%2C%20styles.textFromTo%5D%7D%3ECHICAGO%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5Bstyles.text%2C%20%7BalignItems%3A%20’flex-end’%7D%5D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CFontAwesome%20name%3D%22fighter-jet%22%20size%3D%7B20%7D%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5Bstyles.text%2C%20styles.textFromTo%5D%7D%3ESEATTLE%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FRow%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CRow%20justifyContent%3D%22space-between%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5Bstyles.text%5D%7D%3EAll%20Airports%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5Bstyles.text%5D%7D%3ETacoma%20Intl.%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FRow%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FLinearGradient%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%7D%0A%7D » message= » » highlight= » » provider= »manual »/]

Et le résultat :

Simulator Screen Shot 24 Jan 2017 20.03.26

Je garde pour plus tard la gestion des polices et je passe au composant ProceedAction.

 

<ProceedAction>

Dans ce composant je vais avoir besoin de 2 données :

  • Le prix du vol sélectionné
  • L’id du vol

Pour l’UI, on retrouve du dégradé, du positionnement et de l’accès aux propriétés.

[pastacode lang= »javascript » manual= »import%20React%2C%20%7BComponent%7D%20from%20’react’%3B%0Aimport%20%7BView%2C%20Text%2C%20StyleSheet%2C%20Dimensions%7D%20from%20’react-native’%3B%0Aimport%20LinearGradient%20from%20’react-native-linear-gradient’%3B%0Avar%20MaterialIcons%20%3D%20require(‘react-native-vector-icons%2FMaterialIcons’)%3B%0A%0A%2F%2F%20Styles%0Aconst%20%7Bwidth%2C%20height%7D%20%3D%20Dimensions.get(‘window’)%3B%0Aconst%20styles%20%3D%20StyleSheet.create(%7B%0A%20%20%20%20container%3A%20%7B%0A%20%20%20%20%20%20%20%20width%2C%0A%20%20%20%20%20%20%20%20alignItems%3A%20’center’%2C%0A%20%20%20%20%20%20%20%20position%3A%20’absolute’%2C%0A%20%20%20%20%20%20%20%20top%3A%20height%20-%2060%0A%20%20%20%20%7D%2C%0A%20%20%20%20gradient%3A%20%7B%0A%20%20%20%20%20%20%20%20width%3A%20width%20-%2060%2C%0A%20%20%20%20%20%20%20%20height%3A%2045%2C%0A%20%20%20%20%20%20%20%20justifyContent%3A%20’center’%2C%0A%20%20%20%20%20%20%20%20alignItems%3A%20’center’%2C%0A%20%20%20%20%20%20%20%20borderRadius%3A%2040%2C%0A%20%20%20%20%20%20%20%20flexDirection%3A%20’row’%2C%0A%20%20%20%20%20%20%20%20shadowOffset%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20width%3A%203%2C%20height%3A%203%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20shadowColor%3A%20’%23333’%2C%20shadowOpacity%3A%200.35%2C%20shadowRadius%3A%203%2C%20elevation%3A%205%0A%20%20%20%20%7D%2C%0A%20%20%20%20text%3A%20%7B%0A%20%20%20%20%20%20%20%20backgroundColor%3A%20’transparent’%2C%0A%20%20%20%20%20%20%20%20color%3A%20’white’%2C%0A%20%20%20%20%20%20%20%20fontWeight%3A%20’bold’%2C%0A%20%20%20%20%7D%2C%0A%20%20%20%20icon%3A%20%7B%0A%20%20%20%20%20%20%20%20alignSelf%3A%20’center’%2C%0A%20%20%20%20%20%20%20%20backgroundColor%3A%20’transparent’%0A%20%20%20%20%7D%0A%7D)%3B%0A%0Aexport%20default%20class%20ProceedAction%20extends%20Component%20%7B%0A%20%20%20%20render()%20%7B%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7Bstyles.container%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CLinearGradient%20colors%3D%7B%5B’%232196F3CC’%2C%20’%235C258DCC’%5D%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20style%3D%7Bstyles.gradient%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20start%3D%7B%7Bx%3A%200.0%2C%20y%3A%200.25%7D%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20end%3D%7B%7Bx%3A%201%2C%20y%3A%20.45%7D%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CMaterialIcons%20name%3D%22payment%22%20color%3D%22white%22%20size%3D%7B20%7D%20style%3D%7Bstyles.icon%7D%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7Bstyles.text%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20PROCEED%20%7Bthis.props.price%7C%7C0%7D%24%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FLinearGradient%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%7D%0A%7D » message= » » highlight= » » provider= »manual »/]

Et le résultat temporaire :

Simulator Screen Shot 24 Jan 2017 20.49.31

Je m’attaque maintenant à la partie plus compliquée : la liste des vols.

<FlightList>

Avant de créer ce composant, il va me falloir un Service qui me retourne les données.

[pastacode lang= »javascript » manual= »export%20default%20class%20FlightService%20%7B%0A%20%20%20%20static%20all()%20%7B%0A%20%20%20%20%20%20%20%20return%20Promise.resolve(%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20id%3A%200%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fromTime%3A%20’12%3A00%20am’%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20toTime%3A%20’02%3A36%20pm’%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fromAirport%3A%20’Midway’%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20toAirport%3A%20’Tacoma%20Intl.’%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20price%3A%20341%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20miscs%3A%20%5B’4h34m%20Nonstop’%2C%20’WiFi%2C%20Video’%2C%20’Boieng%20737-900’%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20logo%3A%20’airline-logo’%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%2F*%20….%20*%2F%0A%20%20%20%20%20%20%20%20%5D)%3B%0A%20%20%20%20%7D%0A%7D » message= » » highlight= » » provider= »manual »/]

 

Maintenant que le service est créé je vais l’utiliser dans mon composant :

[pastacode lang= »javascript » manual= »import%20React%2C%20%7BComponent%7D%20from%20’react’%3B%0Aimport%20%7BView%2C%20Text%2C%20StyleSheet%7D%20from%20’react-native’%3B%0A%0A%2F%2F%20App%0Aimport%20FlightService%20from%20%22..%2Fservices%2FFlightService%22%3B%0A%0A%2F%2F%20Styles%0Aconst%20styles%20%3D%20StyleSheet.create(%7B%7D)%0A%0Aexport%20default%20class%20FlightList%20extends%20Component%20%7B%0A%20%20%20%20constructor()%20%7B%0A%20%20%20%20%20%20%20%20super()%3B%0A%20%20%20%20%20%20%20%20this.state%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20flights%3A%20%5B%5D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20componentDidMount()%20%7B%0A%20%20%20%20%20%20%20%20FlightService.all().then(flights%20%3D%3E%20this.setState(%7Bflights%7D))%0A%20%20%20%20%7D%0A%20%20%20%20render()%20%7B%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CView%3E%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%7D%0A%7D » message= » » highlight= » » provider= »manual »/]

Je passe maintenant à l’UI en commençant par définir la position de mon composant. Puis je rajoute l’ombre et le borderRadius.

[pastacode lang= »javascript » manual= »import%20React%2C%20%7BComponent%7D%20from%20’react’%3B%0Aimport%20%7BView%2C%20Text%2C%20StyleSheet%2C%20Dimensions%7D%20from%20’react-native’%3B%0A%0A%2F%2F%20App%0Aimport%20FlightService%20from%20%22..%2Fservices%2FFlightService%22%3B%0A%0A%2F%2F%20Styles%0Aconst%20%7Bwidth%2C%20height%7D%20%3D%20Dimensions.get(‘window’)%3B%0Aconst%20styles%20%3D%20StyleSheet.create(%7B%0A%20%20%20%20container%3A%20%7B%0A%20%20%20%20%20%20%20%20backgroundColor%3A%20’white’%2C%0A%20%20%20%20%20%20%20%20marginHorizontal%3A%2010%2C%0A%20%20%20%20%20%20%20%20borderRadius%3A%207%2C%0A%20%20%20%20%20%20%20%20height%2C%20width%3A%20width%20-%2020%2C%0A%20%20%20%20%20%20%20%20position%3A’absolute’%2C%0A%20%20%20%20%20%20%20%20top%3A%20175%2C%0A%20%20%20%20%20%20%20%20shadowOffset%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20width%3A%201%2C%20height%3A%201%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20shadowColor%3A%20’%23333’%2C%20shadowOpacity%3A%200.35%2C%20shadowRadius%3A%207%2C%20elevation%3A%205%0A%20%20%20%20%7D%0A%7D)%0A%0Aexport%20default%20class%20FlightList%20extends%20Component%20%7B%0A%20%20%20%20constructor()%20%7B%0A%20%20%20%20%20%20%20%20super()%3B%0A%20%20%20%20%20%20%20%20this.state%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20flights%3A%20%5B%5D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20componentDidMount()%20%7B%0A%20%20%20%20%20%20%20%20FlightService.all().then(flights%20%3D%3E%20this.setState(%7Bflights%7D))%0A%20%20%20%20%7D%0A%20%20%20%20render()%20%7B%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7Bstyles.container%7D%3E%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%7D%0A%7D » message= » » highlight= » » provider= »manual »/]

Et pour l’instant mon application ressemble à ça :

Simulator Screen Shot 24 Jan 2017 21.12.40

Je passe donc à l’implémentation de mon composant, version « gros grain ». Je vais créer la partie « Tabs » puis les cartes de résultats.

[pastacode lang= »javascript » manual= »import%20React%2C%20%7BComponent%7D%20from%20’react’%3B%0Aimport%20%7BView%2C%20Text%2C%20StyleSheet%2C%20Dimensions%7D%20from%20’react-native’%3B%0A%0A%2F%2F%20App%0Aimport%20FlightService%20from%20%22..%2Fservices%2FFlightService%22%3B%0Aimport%20ResultListTabs%20from%20′.%2FResultListTabs’%3B%0Aimport%20ResultList%20from%20′.%2FResultList’%3B%0Aimport%20Tab%20from%20′.%2FTab’%3B%0A%0A%2F%2F%20Styles%0Aconst%20%7Bwidth%2C%20height%7D%20%3D%20Dimensions.get(‘window’)%3B%0Aconst%20styles%20%3D%20StyleSheet.create(%7B%0A%20%20%20%20container%3A%20%7B%0A%20%20%20%20%20%20%20%20backgroundColor%3A%20’white’%2C%0A%20%20%20%20%20%20%20%20marginHorizontal%3A%2010%2C%0A%20%20%20%20%20%20%20%20borderRadius%3A%207%2C%0A%20%20%20%20%20%20%20%20height%2C%20width%3A%20width%20-%2020%2C%0A%20%20%20%20%20%20%20%20position%3A’absolute’%2C%0A%20%20%20%20%20%20%20%20top%3A%20175%2C%0A%20%20%20%20%20%20%20%20shadowOffset%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20width%3A%201%2C%20height%3A%201%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20shadowColor%3A%20’%23333’%2C%20shadowOpacity%3A%200.35%2C%20shadowRadius%3A%207%2C%20elevation%3A%205%0A%20%20%20%20%7D%0A%7D)%0A%0Aexport%20default%20class%20FlightList%20extends%20Component%20%7B%0A%20%20%20%20constructor()%20%7B%0A%20%20%20%20%20%20%20%20super()%3B%0A%20%20%20%20%20%20%20%20this.state%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20flights%3A%20%5B%5D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20componentDidMount()%20%7B%0A%20%20%20%20%20%20%20%20FlightService.all().then(flights%20%3D%3E%20this.setState(%7Bflights%7D))%0A%20%20%20%20%7D%0A%20%20%20%20render()%20%7B%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7Bstyles.container%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CResultListTabs%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CTab%20icon%3D%22flight%22%20text%3D%22219%24%22%20action%3D%7Bthis._foo.bind(this)%7D%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CTab%20icon%3D%22directions-railway%22%20text%3D%22102%24%22%20action%3D%7Bthis._foo.bind(this)%7D%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CTab%20icon%3D%22directions-bus%22%20text%3D%2275%24%22%20action%3D%7Bthis._foo.bind(this)%7D%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FResultListTabs%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CResultList%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20flights%3D%7Bthis.state.flights%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20onSelectItem%3D%7Bflight%20%3D%3E%20this._selectFlight(flight)%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%7D%0A%20%20%20%20_foo()%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20NOOP%0A%20%20%20%20%7D%0A%20%20%20%20_selectFlight(flight)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20NOOP%0A%20%20%20%20%7D%0A%7D » message= » » highlight= » » provider= »manual »/]

<ResultListTabs> et <Tab>

ResultListTabs va se charger de gérer la logique des tabs. Je pourrais bien sur m’appuyer sur un package existant de la communauté, mais le but de cet article est aussi de vous montrer la facilité d’écriture des composants avec React Native.

Tabs quant à lui se chargera de la mise en page.

[pastacode lang= »javascript » manual= »import%20React%2C%20%7BComponent%7D%20from%20’react’%3B%0Aimport%20%7BView%2C%20Text%2C%20StyleSheet%2C%20TouchableOpacity%7D%20from%20’react-native’%3B%0A%0A%2F%2F%20App%0Aimport%20Row%20from%20′.%2FRow’%3B%0A%0A%2F%2F%20Styles%0Aconst%20styles%20%3D%20StyleSheet.create(%7B%0A%20%20%20%20button%3A%20%7B%0A%20%20%20%20%20%20%20%20height%3A%2040%2C%0A%20%20%20%20%20%20%20%20flex%3A%201%0A%20%20%20%20%7D%0A%7D)%3B%0A%0Aexport%20default%20class%20ResultListTabs%20extends%20Component%20%7B%0A%20%20%20%20constructor()%20%7B%0A%20%20%20%20%20%20%20%20super()%3B%0A%20%20%20%20%20%20%20%20this.state%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20selectedTabIdx%3A%200%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20render()%20%7B%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CRow%20justifyContent%3D%22space-between%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7Bthis.props.children.map(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(tab%2C%20idx)%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20tabWithProps%20%3D%20React.cloneElement(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tab%2C%20%7Bselected%3A%20this.state.selectedTabIdx%20%3D%3D%3D%20idx%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CTouchableOpacity%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20key%3D%7Bidx%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20onPress%3D%7Bthis._selectTab.bind(this%2C%20tab%2C%20idx)%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20style%3D%7Bstyles.button%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7BtabWithProps%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FTouchableOpacity%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FRow%3E%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%7D%0A%20%20%20%20_selectTab(tab%2C%20idx)%20%7B%0A%20%20%20%20%20%20%20%20this.setState(%7BselectedTabIdx%20%3A%20idx%7D)%3B%0A%20%20%20%20%20%20%20%20tab.props.action()%3B%0A%20%20%20%20%7D%0A%7D » message= »ResultListTabs » highlight= » » provider= »manual »/]

Note : Ce composant se charge de garder l’onglet sélectionné. Il a donc besoin de garder dans son état une variable « selectedTabIdx » et de passer la propriété selected au composant <Tab>. Cependant l’attribut « props » d’un composant est immutable, et j’ai donc besoin de cloner le composant avec React.cloneElement.

[pastacode lang= »javascript » manual= »import%20React%2C%20%7BComponent%7D%20from%20’react’%3B%0Aimport%20%7BView%2C%20Text%2C%20StyleSheet%7D%20from%20’react-native’%3B%0Avar%20MaterialIcons%20%3D%20require(‘react-native-vector-icons%2FMaterialIcons’)%3B%0A%0A%2F%2F%20Styles%0Aconst%20styles%20%3D%20StyleSheet.create(%7B%0A%20%20%20%20container%3A%20%7B%0A%20%20%20%20%20%20%20%20flexDirection%3A%20’row’%2C%0A%20%20%20%20%20%20%20%20backgroundColor%3A%20’transparent’%2C%0A%20%20%20%20%20%20%20%20justifyContent%3A%20’center’%2C%0A%20%20%20%20%20%20%20%20alignItems%3A%20’center’%2C%0A%20%20%20%20%20%20%20%20height%3A%2040%2C%0A%20%20%20%20%20%20%20%20borderBottomWidth%3A%201%2C%0A%20%20%20%20%20%20%20%20borderBottomColor%3A%20’%23CCC’%0A%20%20%20%20%7D%2C%0A%20%20%20%20icon%3A%20%7B%0A%20%20%20%20%20%20%20%20color%3A%20’%23CCC’%0A%20%20%20%20%7D%2C%0A%20%20%20%20text%3A%20%7B%0A%20%20%20%20%20%20%20%20color%3A%20’%23CCC’%2C%0A%20%20%20%20%20%20%20%20fontWeight%3A%20’bold’%2C%0A%20%20%20%20%20%20%20%20fontSize%3A%2018%0A%20%20%20%20%7D%2C%0A%20%20%20%20selectedContainer%3A%20%7B%0A%20%20%20%20%20%20%20%20borderBottomWidth%3A%202%2C%0A%20%20%20%20%20%20%20%20borderBottomColor%3A%20’%236A1B9A’%0A%20%20%20%20%7D%2C%0A%20%20%20%20selectedText%3A%20%7B%0A%20%20%20%20%20%20%20%20color%3A%20’%236A1B9A’%0A%20%20%20%20%7D%0A%7D)%3B%0A%0Aexport%20default%20class%20Tab%20extends%20Component%20%7B%0A%20%20%20%20render()%20%7B%0A%20%20%20%20%20%20%20%20var%20selectedStyle%20%3D%20this.props.selected%20%3F%20styles.selectedContainer%20%3A%20%7B%7D%3B%0A%20%20%20%20%20%20%20%20var%20selectedTextStyle%20%3D%20this.props.selected%20%3F%20styles.selectedText%20%3A%20%7B%7D%3B%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7B%5Bstyles.container%2C%20selectedStyle%5D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CMaterialIcons%20name%3D%7Bthis.props.icon%7D%20size%3D%7B20%7D%20style%3D%7B%5Bstyles.icon%2C%20selectedTextStyle%5D%7D%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5Bstyles.text%2C%20selectedTextStyle%5D%7D%3E%7Bthis.props.text%7D%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%7D%0A%7D » message= »Tab » highlight= » » provider= »manual »/]

Et le rendu à cette étape :

Simulator Screen Shot 25 Jan 2017 20.15.01

Je me rapproche de mon UI cible et je termine par la liste des résultats.

<ResultList>

La liste des résultats va itérer sur la liste des vols fournie par le service. Pour chaque vol nous allons afficher une ligne dans une <ScrollView>. A chaque action sur une ligne nous allons forcer le layout à générer une animation grâce à :

LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);

Enfin, je vais cabler la logique en faisant descendre l’event ‘onSelectFlight’ dans mon arbre de composant.

Note : J’aurais pu (et surement du) utiliser le composant ListView, mais pour les besoins de cet article j’ai préféré itérer directement sur mon array.

Pour l’UI cela nous donne

[pastacode lang= »javascript » manual= »render()%20%7B%0A%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CScrollView%20style%3D%7B%7BpaddingHorizontal%3A%2011%7D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20this.props.flights.map(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(flight%2C%20idx)%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20selected%20%3D%20this.state.selectedFlightIdx%20%3D%3D%3D%20idx%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20style%20%3D%20selected%20%3F%20styles.selected%20%3A%20styles.normal%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20textStyle%20%3D%20selected%20%3F%20styles.textSelected%20%3A%20styles.text%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20textBold%20%3D%20%20selected%20%3F%20styles.textSelectedBold%20%3A%20styles.textBold%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CTouchableOpacity%20key%3D%7Bidx%7D%20onPress%3D%7Bthis._select.bind(this%2C%20idx)%7D%20style%3D%7Bstyle%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7Bselected%20%3F%20%3CLinearGradient%20colors%3D%7B%5B’%23B993D666’%2C%20’%238CA6DB66’%5D%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20style%3D%7Bstyles.gradient%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20start%3D%7B%7Bx%3A%200.0%2C%20y%3A%200.25%7D%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20end%3D%7B%7Bx%3A%201%2C%20y%3A%20.45%7D%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3E%3C%2FLinearGradient%3E%20%3A%20null%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7B%7BflexDirection%3A%20’row’%2C%20paddingTop%3A%2011%2C%20paddingLeft%3A%207%7D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7B%7Bflex%3A%201%7D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5BtextStyle%2C%20%7BfontSize%3A%2024%7D%5D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7Bselected%20%3F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CFontAwesome%20name%3D%22check-circle%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20size%3D%7B15%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20color%3D%7B’%236A1B9A’%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%3E%20%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20′.’%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7B%7Bflex%3A%2010%2C%20paddingHorizontal%3A%2011%2C%20flexDirection%3A%20’row’%2C%20justifyContent%3A%20’space-between’%7D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5BtextStyle%2C%20%7BfontSize%3A%2015%7D%2C%20textBold%5D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7Bflight.fromTime%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7BtextStyle%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7Bflight.fromAirport%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7B%7BjustifyContent%3A%20’center’%7D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CFontAwesome%20name%3D%22fighter-jet%22%20size%3D%7B15%7D%20color%3D%7Bselected%20%3F%20’%236A1B9A’%20%3A%20’%23CCC’%7D%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5BtextStyle%2C%20%7BfontSize%3A%2015%7D%2C%20textBold%5D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7Bflight.toTime%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7BtextStyle%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7Bflight.toAirport%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7B%7Bflex%3A%204%2C%20justifyContent%3A%20’center’%2C%20alignItems%3A%20’flex-end’%2C%20paddingRight%3A%207%7D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CText%20style%3D%7B%5BtextStyle%2C%20%7Bcolor%3A%20’%23AAA’%7D%2C%20textBold%2C%20%7BfontSize%3A%2018%7D%5D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7Bflight.price%7D%24%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FText%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7Bselected%20%3F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7B%7BflexDirection%3A%20’row’%2C%20paddingHorizontal%3A%2014%2C%20marginTop%3A%2014%7D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7B%7Bflex%3A%201%7D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20flight.miscs.map((text%2C%20key)%20%3D%3E%20%3CText%20key%3D%7Bkey%7D%20style%3D%7B%7Bcolor%3A%20’%236A1B9AAA’%7D%7D%3E%7Btext%7D%3C%2FText%3E)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CView%20style%3D%7B%7Bflex%3A%201%7D%7D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CImage%20source%3D%7B%7Buri%3A%20’airline’%2C%20isStatic%3A%20true%2C%20width%3A%20160%2C%20height%3A%2055%7D%7D%20%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FView%3E%20%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20null%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FTouchableOpacity%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FScrollView%3E%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%7D » message= » » highlight= » » provider= »manual »/]

Avec le « cablage », on obtient le résultat suivant :

Jan-29-2017 13-21-57

 

et sur Android (émulateur Genymotion):

Screen Shot 2017-01-30 at 11.35.44

Améliorations

Voilà c’est tout pour cet article, cependant je ne suis pas 100% ISO avec le prototype du départ. Les améliorations possibles sont donc :

  • Utiliser la ListView pour détecter facilement le scroll dans la liste et agir sur le composants ProceedActions et la taille du header.
  • Créer à la main l’animation lors du clic sur un vol.

Un bon exercice si vous voulez creuser plus dans React Native.

Questions

Vous avez des questions ou des remarques ? N’hésitez pas à m’en faire part dans les commentaires 😉

Vous voulez en savoir plus sur React Native ? Je vous propose ma formation personnalisée pour React Native.

Le code est disponible sur Github.

 

A plus sur le blog de We Are One,

Florian

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *