Le package photo_view est une solution essentielle dans l'écosystème Flutter pour implémenter des visualiseurs d'images réactifs. Il encapsule la complexité de la reconnaissance des gestes (pinch-to-zoom, double-tap, panning) dans un widget déclaratif, idéal pour les galeries photo, les aperçus de produits ou les visualiseurs de documents.
Caractéristiques techniques principales
Le widget PhotoView se distingue par sa capacité à gérer nativement les interactions complexes tout en offrant une API hautement configurable :
- Interactions gestuelles : Support natif du zoom par pincement, du double-clic et du déplacement par glissement.
- Contrôle des échelles : Définition précise des limites de zoom (min/max) pour éviter les déformatinos excessives.
- Transitions Hero : Intégration fluide avec le système de navigation de Flutter pour les animations entre les listes et les détails.
- Contrôle programmatique : Manipulation de l'état (position, échelle) via un contrôleur dédié.
Intégration et utilisation de base
Ajoutez la dépendance dans votre fichier pubspec.yaml :
dependencies:
photo_view: ^0.15.0
Exécutez ensuite la commande de synchronisation :
flutter pub get
Voici comment instancier un visualiseur basique avec des contraintes d'échelle personnalisées :
import 'package:photo_view/photo_view.dart';
PhotoView(
imageProvider: const NetworkImage('https://cdn.exemple.com/assets/panorama.jpg'),
minScale: PhotoViewComputedScale.contained * 0.5,
maxScale: PhotoViewComputedScale.covered * 4.0,
enableRotation: false,
)
Implémentation d'une galerie d'images
Pour afficher des collections multiples avec un balayage horizontal, PhotoViewGallery.builder est l'approche recommandée. Elle optimise la mémoire en ne chargeant que les pages visibles.
PhotoViewGallery.builder(
itemCount: mediaCollection.length,
pageController: PageController(),
builder: (BuildContext context, int pageIndex) {
final asset = mediaCollection[pageIndex];
return PhotoViewGalleryPageOptions(
imageProvider: NetworkImage(asset.remoteUrl),
initialScale: PhotoViewComputedScale.contained,
heroAttributes: PhotoViewHeroAttributes(tag: asset.uniqueId),
);
},
)
Personnalisations avancées
Manipulation programmatique via le contrôleur
Le PhotoViewController permet de déclencher des zooms ou des déplacements via la logique métier :
final transformCtrl = PhotoViewController();
// Ajustement de l'échelle
transformCtrl.scale = 3.5;
// Déplacement du point de focalisation
transformCtrl.position = const Offset(150.0, -50.0);
Gestion des états de chargement et d'erreur
Il est crucial de fournir un retour visuel lors du chargement d'assets distants volumineux :
PhotoView(
imageProvider: const NetworkImage('https://api.exemple.com/v1/images/heavy_file.jpg'),
loadingBuilder: (context, progress) {
if (progress == null) return const Center(child: Text('Connexion...'));
final double ratio = progress.cumulativeBytesLoaded / (progress.expectedTotalBytes ?? 1);
return Center(child: LinearProgressIndicator(value: ratio));
},
errorBuilder: (context, error, stack) => const Center(
child: Icon(Icons.broken_image, color: Colors.redAccent, size: 48),
),
)
Résolution de problèmes courants
Perte de qualité lors du zoom
Si l'image devient pixellisée, assurez-vous d'utiliser des assets en haute résolution et d'augmenter la limite supérieure de l'échelle :
PhotoView(
imageProvider: const AssetImage('assets/ultra_hd_map.jpg'),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 5.0,
)
Conflits de gestes dans les ScrollViews
Lorsque le visualiseur est imbriqué dans une liste défilante, les gestes peuvent entrer en conflit. L'ajustement du comportement du détecteur de gestes résout ce problème :
PhotoView(
imageProvider: const AssetImage('assets/diagram.jpg'),
gestureDetectorBehavior: HitTestBehavior.translucent,
)