Image widget 是 Flutter 中最常用的 widget 之一,但我相信我們沒有充分利用它的功能,僅僅顯示一個圖片是不夠的,你還應該給用戶他們需要的最佳體驗!
在這篇文章中,我將談論一些圖像技巧和最佳實踐,以獲得更好的性能和用戶體驗。
這些技巧是:
WebP 是下一代圖像格式,它比 PNG 和 JPEG 小約 25%,并且比其他格式快。
這意味著,你的應用程序將使用更少的內存,構建速度更快。
這里有一些基準:
圖片
圖片
Image.asset( // 'image.jpg', 'image.webp', // PREFER);
它可以防止應用程序出現布局偏移
圖片
之前——之后
Imagework( imageUrl, width: 200, height: 150,);
圖片
圖片
你的圖片可能會導致設備內存膨脹,這是因為,盡管它們在 UI 中占據相對較小的一部分,Flutter 還是會以全分辨率渲染它們,從而消耗大量內存。
為了避免這種問題,可以使用 cacheWidth 或 cacheHeight 參數對指定大小的圖像進行解碼。
此外,我們可以使用 Flutter 開發者工具輕松檢測超大圖像。
如果圖像過大,它會反轉圖像,使其顛倒。
注意!緩存大小不應該小于小部件的大小,否則,由于分辨率低,它看起來像素化!
Imagework( imageUrl, cacheWidth: 100, cacheHeight: 150,);
如果你在顯示圖像之前緩存它們,Flutter 將跳過構建的處理步驟并立即顯示它們。
圖片
class MyImage extends StatefulWidget { const MyImage({super.key}); @override State createState() => _MyImageState();}class _MyImageState extends State { late final Image myImage; @override void initState() { super.initState(); myImage = Image.asset('path'); } @override void didChangeDependencies() { super.didChangeDependencies(); precacheImage(myImage.image, context); } @override Widget build(BuildContext context) { return myImage; }}
突然彈出圖像不是預期的行為,用戶可能會因為網絡連接不足而錯過圖像并向下滾動,或者可能在屏幕上看到一些空白,等等。我們應該始終通知用戶圖像正在加載。
圖片
return Imagework( imageUrl, loadingBuilder: (_, child, event) { if (event == null) return child; return const Center(child: CircularProgressIndicator()); },);
我們也可以顯示進度百分比,而不是無限加載,這樣對用戶來說更有用。
圖片
return Imagework( imageUrl, loadingBuilder: (_, child, event) { if (event == null) return child; return Center( child: CircularProgressIndicator( value: event.cumulativeBytesLoaded / (event.expectedTotalBytes ?? 0), ), ); },);
顯示進度條是好的,但并不是最好的選擇,顯示閃爍效果(Shimmer)要比顯示進度條好得多。
圖片
return Imagework( imageUrl, height: 200, width: 350, loadingBuilder: (_, child, event) { if (event == null) return child; return const Shimmer( height: 200, width: 350, ); });// Most Basic Shimmerclass Shimmer extends StatefulWidget { const Shimmer({ super.key, this.width, this.height, this.minOpacity = 0.015, this.maxOpacity = 0.15, this.borderRadius = const BorderRadius.all(Radius.circular(4)), this.child, }); final double? width; final double? height; final double minOpacity; final double maxOpacity; final BorderRadius? borderRadius; final Widget? child; @override State createState() => _ShimmerState();}class _ShimmerState extends State with SingleTickerProviderStateMixin { late final AnimationController controller; @override void initState() { super.initState(); controller = AnimationController( vsync: this, duration: const Duration(seconds: 1), lowerBound: widget.minOpacity, upperBound: widget.maxOpacity, )..repeat(reverse: true); } @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return RepaintBoundary( child: FadeTransition( opacity: controller, child: Container( width: widget.width, height: widget.height, decoration: BoxDecoration( color: Colors.black, borderRadius: widget.borderRadius, ), child: widget.child, ), ), ); }}
我創建了一個簡單的 shimmer 小部件,但你可以從官方文檔中學習如何創建高級版本的 shimmer 效果。
?
官方文檔:創建 shimmer 加載效果(https://docs.flutter.dev/cookbook/effects/shimmer-loading)
為了改善用戶體驗,可以使用哈希代碼顯示圖像的模糊版本,而不是在圖像加載時顯示空白的灰色區域。
圖片
https://blurha.sh/
return const SizedBox( width: 350, height: 200, child: BlurHash( hash: hashCode, imageFit: BoxFit.cover, image: imageUrl, ),);
默認情況下,圖片加載后立即顯示,這對我們的視覺體驗來說非常糟糕,為了改善這一點,我們可以用一個小的漸入動畫來顯示它們。
我們可以使用 FadeInImage 來實現這個功能。
它需要字節或資源作為占位符,在這個例子中,我將使用 transparent_image 包來獲取透明圖像字節。
我們還可以使用 cached_network_image 包來實現這一點,以及更多。
return FadeInImage.memoryNetwork( image: imageUrl, placeholder: kTransparentImage,);// 或者return CachedNetworkImage( imageUrl: imageUrl,);
為了避免每次下載相同的圖片,我們可以緩存第一次下載的圖片并重復使用,為了實現這一點,我們可以創建自己的緩存機制,或者我們可以直接使用 cached_network_image。
它緩存網絡圖像,默認情況下自動顯示它們的淡入效果,并提供了更多的圖像控制。
Image widget 沒有 const 構造函數,雖然這在大多數情況下都不是問題,但我們可以通過將它包裝在自定義 widget 中來修復它。
它不僅可以讓我們的應用程序更具性能,而且我們還可以根據我們的意愿定制小部件,例如,我們可以為每個圖像小部件創建一個全局解決方案,而不是每次都處理 error/loading 情況。
enum _ImageType { asset, network }class AppImage extends StatelessWidget { const AppImage.asset( this.image, { super.key, }) : type = _ImageType.asset; const AppImagework( this.image, { super.key, }) : type = _ImageTypework; final String image; final _ImageType type; @override Widget build(BuildContext context) { const errorWidget = Icon(Icons.error); return switch (type) { _ImageType.asset => Image.asset( image, errorBuilder: (_, __, ___) => errorWidget, ), _ImageTypework => Imagework( image, errorBuilder: (_, __, ___) => errorWidget, ), }; }}/// 使用const AppImage.asset(''), // OKconst Image.asset(''), // 錯誤?。mage 沒有const構造函數// 正如您所知,擁有 const 的小部件非常重要以獲得更好的性能。
有時候由于網絡連接不好或其他原因,圖片無法第一次加載,顯示錯誤消息是好的,但這還不夠,如果我們想把應用的 UX 提升到另一個層次,我們應該讓用戶重新加載圖片,并繼續使用應用,而不會遇到任何麻煩。
圖片
class MyImage extends StatefulWidget { const MyImage({super.key}); @override State createState() => _MyImageState();}class _MyImageState extends State { int attempt = 0; @override Widget build(BuildContext context) { return CachedNetworkImage( imageUrl: imageUrl, cacheKey: '$attempt', height: 200, width: 250, fit: BoxFit.cover, errorWidget: (_, __, ___) { return RetryWidget( height: 200, width: 250, onTap: () => setState(() => attempt++), ); }, ); }}// Just a basic retry buttonclass RetryWidget extends StatelessWidget { const RetryWidget({ super.key, required this.height, required this.width, required this.onTap, }); final double? height; final double? width; final void Function() onTap; @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( height: height, width: width, alignment: Alignment.center, decoration: const BoxDecoration(color: Colors.black12), child: const Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.image_not_supported, size: 20), SizedBox(height: 12), Padding( padding: EdgeInsets.symmetric(horizontal: 12), child: Text( "Image couldn't load, tap here to retry", textAlign: TextAlign.center, style: TextStyle(fontSize: 14, color: Colors.black), ), ), ], ), ), ); }}
僅僅展示圖片是不夠的!您還應該為用戶提供他們需要的最佳體驗!因此,我強烈建議您創建自己的自定義圖片 widget,將它們隨意組合并自由使用!
原文:https://medium.com/itnext/12-image-tips-and-best-practices-for-the-best-ux-performance-in-flutter-e7a1b2b1da2a&strip=0&vwsrc=1&referer=medium-parser
本文鏈接:http://www.www897cc.com/showinfo-26-22455-0.html在 Flutter 中實現最佳 UX 性能的 12 個圖像技巧和最佳實踐
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: Json格式弊端及優化方案