Cours React Native · Module 6: Photos, appareil photo et son

expo-image - Affichage optimal des images

2 min de lecture ·
Dans cette leçon6

Bienvenue dans la Galerie des Cristaux ! Tu vas apprendre à gérer le multimédia dans les applications mobiles.

Installation d'expo-image

npx expo install expo-image

Utilisation de base

import { Image } from 'expo-image';
import { StyleSheet, View } from 'react-native';

function ImageGallery() {
  return (
    <View style={styles.container}>
      {/* Image depuis une URL */}
      <Image
        source={{ uri: 'https://atlantis.app/images/crystal.jpg' }}
        style={styles.image}
        contentFit="cover"
        transition={300}
      />

      {/* Image locale */}
      <Image
        source={require('@/assets/images/pearl.png')}
        style={styles.image}
        contentFit="contain"
      />

      {/* Avec placeholder et flou */}
      <Image
        source={{ uri: 'https://atlantis.app/images/large.jpg' }}
        placeholder={blurhash}
        style={styles.image}
        contentFit="cover"
        transition={500}
      />
    </View>
  );
}

const blurhash = 'L6PZfSi_.AyE_3t7t7R**0o#DgR4';

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  image: {
    width: '100%',
    height: 200,
    borderRadius: 12,
  },
});

contentFit (anciennement resizeMode)

// Différents modes d'ajustement
<Image source={source} contentFit="cover" />   // Remplit, peut rogner
<Image source={source} contentFit="contain" /> // Entièrement visible, peut avoir des marges
<Image source={source} contentFit="fill" />    // Étire aux dimensions
<Image source={source} contentFit="none" />    // Dimensions d'origine
<Image source={source} contentFit="scale-down" /> // contain ou none (le plus petit)

Blurhash et Placeholder

import { Image } from 'expo-image';

// Blurhash - placeholder compact
const blurhash = 'L6PZfSi_.AyE_3t7t7R**0o#DgR4';

function OptimizedImage() {
  return (
    <Image
      source={{ uri: 'https://example.com/image.jpg' }}
      placeholder={blurhash}
      placeholderContentFit="cover"
      style={styles.image}
      transition={500}
    />
  );
}

Mise en cache

import { Image } from 'expo-image';

// Paramètres de cache
<Image
  source={{ uri: imageUrl }}
  cachePolicy="memory-disk" // memory, disk, memory-disk, none
  style={styles.image}
/>

// Préchargement
import { Image } from 'expo-image';

async function preloadImages() {
  const urls = [
    'https://example.com/image1.jpg',
    'https://example.com/image2.jpg',
  ];

  await Promise.all(urls.map((url) => Image.prefetch(url)));
}

Liste d'images avec FlatList

interface ImageItem {
  id: string;
  uri: string;
  title: string;
}

function ImageList() {
  const [images, setImages] = useState<ImageItem[]>([]);

  return (
    <FlatList
      data={images}
      numColumns={2}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => (
        <Pressable style={styles.imageCard}>
          <Image
            source={{ uri: item.uri }}
            style={styles.gridImage}
            contentFit="cover"
            transition={200}
          />
          <Text style={styles.imageTitle}>{item.title}</Text>
        </Pressable>
      )}
    />
  );
}

expo-image est nettement plus performant que le composant Image standard de React Native !

Code de cette leçon : App.tsx
import React, { useState } from 'react';
import { View, Text, FlatList, Pressable, StyleSheet } from 'react-native';
import { Image } from 'expo-image';

interface ImageItem {
  id: string;
  uri: string;
  title: string;
}

export default function App() {
  const [images] = useState<ImageItem[]>([
    { id: '1', uri: 'https://picsum.photos/200?1', title: 'Cristal' },
    { id: '2', uri: 'https://picsum.photos/200?2', title: 'Perle' },
  ]);

  return (
    <FlatList
      data={images}
      numColumns={2}
      keyExtractor={(item) => item.id}
      contentContainerStyle={styles.grid}
      renderItem={({ item }) => (
        <Pressable style={styles.card}>
          {/* TODO : ajoute une <Image> de expo-image qui :
              - a source={{ uri: item.uri }}
              - utilise le style styles.image
              - a contentFit="cover"
              - a transition={200} pour un fondu enchaîné en douceur */}

          <Text style={styles.title}>{item.title}</Text>
        </Pressable>
      )}
    />
  );
}

const styles = StyleSheet.create({
  grid: { padding: 8 },
  card: { flex: 1, margin: 4 },
  image: {
    width: '100%',
    height: 150,
    borderRadius: 12,
  },
  title: {
    color: '#aed6f1',
    textAlign: 'center',
    marginTop: 6,
  },
});

Entrées de la documentation utilisées dans cette leçon

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Quelle valeur de contentFit remplit le conteneur, en rognant potentiellement l'image ?

  2. 2. À quoi sert le blurhash dans expo-image ?

Tâches pratiques dans le jeu

  • Tri horizontal

    Ordonne le préchargement d'une image :

  • Éditeur de code

    Complète le code de la FlatList avec expo-image.

Articles utiles