xnz_image 0.2.2 copy "xnz_image: ^0.2.2" to clipboard
xnz_image: ^0.2.2 copied to clipboard

Flutter image component for unified loading, downloading, and caching of network/memory/file/asset images, with extensible SVG/AVIF format support.

XNZImage #

English | 中文

A Flutter image loading package with unified rendering and cache management. It supports network, memory, file, and asset image sources, and provides an extensible architecture for extra formats.

Overview #

This repository uses a core + extension architecture:

  • xnz_image: main public API (XNZNetworkImage, XNZMemoryImage, XNZFileImage, XNZAssetImage, XNZCacheManager, etc.)
  • xnz_image_core: internal capabilities (cache, downloader, extension mechanism)
  • xnz_image_svg: SVG support extension
  • xnz_image_avif: AVIF support extension

Installation #

1) Base package #

dependencies:
  xnz_image: ^0.2.2

2) Optional extensions #

dependencies:
  xnz_image: ^0.2.2
  xnz_image_svg: ^0.2.2
  xnz_image_avif: ^0.2.2

For local development in this monorepo, you may use path dependencies.

Register Extensions #

import 'package:flutter/widgets.dart';
import 'package:xnz_image/xnz_image.dart';
import 'package:xnz_image_svg/xnz_image_svg.dart';
import 'package:xnz_image_avif/xnz_image_avif.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  XNZImageLogs.showLogs = true;
  XNZImageMemoryObserver().init();

  XNZImage.support(XNZImageSvg());
  XNZImage.support(XNZImageAvif());

  runApp(const MyApp());
}

Logging #

Runtime logs are now normalized to:

  • [module][action]
  • [module][action][key=value,...]

Example:

[XNZImageDownloader][task_start][requestKey=...,url=https://...]

XNZImageLogs.event(module, action, fields: {...}) is recommended for internal/extension code. XNZImageLogs.setInterceptor(...) supports both interceptor signatures:

  • void Function(String tag, String message) (legacy compatible)
  • bool Function(String tag, String message) (true means default output is intercepted)

Observable Events By Source #

  • Network (XNZNetworkImage / XNZNetworkImageProvider)
    • load status: load_status_downloading, load_status_complete, load_status_failed
    • cache path: get_memory_cache_hit|miss, get_disk_cache_hit|miss
    • download path: task_start, task_complete, task_failed, task_reuse_shared
    • decode path: decode_probe, decode_success, decode_failed, decode_failed_final
  • Memory (XNZMemoryImage / XNZMemoryImageProvider)
    • widget flow: build_start, resolve_complete, display_failed
    • decode path: decode_probe, decode_success, decode_failed, load_failed
  • File (XNZFileImage / XNZFileImageProvider)
    • widget flow: build_start, resolve_complete, display_failed
    • decode path: decode_probe, decode_success, decode_failed, load_failed
  • Asset (XNZAssetImage / XNZAssetImageProvider)
    • widget flow: build_start, resolve_complete, display_failed
    • decode path: decode_probe, decode_success, decode_failed, load_failed

Notes:

  • download_* and network cache hit/miss events are network-only by design.
  • decode_probe includes format and likelyImage, useful for quick format mismatch diagnosis.
  • delegated/custom provider display failures emit XNZProxyImageStreamCompleter.display_failed.

Supported Formats #

  • Default (xnz_image only): common bitmap formats such as png, jpg, jpeg, gif, webp, bmp
  • With xnz_image_svg registered: svg, svgz
  • With xnz_image_avif registered: avif, avifs (including animated AVIF duration override)

Basic Widgets #

Network #

XNZNetworkImage(
  imageUrl: 'https://picsum.photos/800/480',
  width: 300,
  height: 180,
  fit: BoxFit.cover,
)

Memory #

XNZMemoryImage(
  bytes: yourBytes,
  width: 300,
  height: 180,
  fit: BoxFit.cover,
)

File #

XNZFileImage(
  file: File('/path/to/local/image.avif'),
  width: 300,
  height: 180,
  fit: BoxFit.cover,
)

Asset #

XNZAssetImage(
  assetName: 'assets/images/banner.avif',
  width: 300,
  height: 180,
  fit: BoxFit.cover,
)

Use With Flutter Image #

Image(
  image: XNZNetworkImageProvider('https://picsum.photos/800/480'),
  width: 300,
  height: 180,
  fit: BoxFit.cover,
)

Authenticated Network Requests #

XNZNetworkImage and XNZNetworkImageProvider support optional headers.

XNZNetworkImage(
  imageUrl: 'https://example.com/private/image.png',
  headers: {'Authorization': 'Bearer <token>'},
  cacheKeyStrategy: XNZCacheKeyStrategy.urlAndHeaders,
)

Cache Key Strategy #

cacheKeyStrategy controls cache isolation behavior:

  • XNZCacheKeyStrategy.urlOnly (default): URL-only cache key, better hit-rate
  • XNZCacheKeyStrategy.urlAndHeaders: URL+headers cache key, safer isolation

Note: request de-duplication always uses URL+headers internally to avoid mixing in-flight downloads from different header contexts.

Animated Image Playback #

XNZAnimatedImage decodes frames and plays on a timeline. It is suitable for GIF / Animated WebP / APNG, and can also decode animated AVIF when AVIF support is registered.

Highlights #

  • Timeline sync: position, progress, frameIndex
  • Playback control: play, pause, resume, replay
  • Callbacks: onLoaded, onCompleted
  • Loop control: loop
  • Error fallback: errorBuilder

Maintenance Updates (2026-05-12) #

  • Cache-key hashing is now split by runtime:
    • Web keeps FNV-1a 32-bit to avoid JS precision pitfalls.
    • IO platforms use FNV-1a 64-bit to reduce cache-collision risk.
  • Animated network bytes loading on IO now goes through the same downloader/cache pipeline as normal network images (XNZUrlRequest + XNZImageDownloader + XNZCacheManager), so cacheKeyStrategy behavior is consistent.
  • AVIF codec keys now use process-local monotonically increasing integers instead of object-hash-derived values, reducing native decoder key-collision risk.
  • AVIF async init/decode guardrails were improved (explicit init error propagation and safer completer handling).
  • Added regression tests for:
    • unified IO animated cache-path loading;
    • AVIF codec key monotonicity.

Maintenance Updates (2026-05-11) #

  • Optimized animated memory cache-key generation: memory bytes fingerprints are now cached by bytes identity to avoid repeated full-byte hashing on frequent rebuilds.
  • Refactored XNZAnimatedImage internals into lib/src/animated/ modules (loader/decoder/cache-key/provider-context/models/controller/cache) to reduce single-file complexity.
  • Unified resolve/render flow for XNZAssetImage, XNZMemoryImage, XNZFileImage, and XNZNetworkImage via shared helpers, reducing template duplication and future drift risk.
  • Public API remains backward compatible.

Example #

final controller = XNZAnimatedImageController();

XNZAnimatedImage(
  image: XNZNetworkImageProvider('https://example.com/demo.gif'),
  controller: controller,
  autoPlay: true,
  loop: true,
  fit: BoxFit.contain,
  onLoaded: (duration, fps, frameCount) {
    debugPrint('duration=$duration fps=$fps frames=$frameCount');
  },
  onCompleted: (completedLoops) {
    debugPrint('completedLoops=$completedLoops');
  },
  loadingBuilder: (_) => const Center(child: CircularProgressIndicator()),
  errorBuilder: (context, error, stackTrace) {
    return const Center(child: Text('Animated image load failed'));
  },
)

Unified Render Hook (renderBuilder) #

Use renderBuilder to wrap default rendering behavior for bitmap and custom formats:

XNZNetworkImage(
  imageUrl: url,
  renderBuilder: (context, child) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(12),
      child: child,
    );
  },
)

If renderBuilder returns null, the widget falls back to default rendering.

Cache Manager #

import 'package:xnz_image/xnz_image.dart';

Future<void> printCacheUsage() async {
  final cacheManager = XNZCacheManager();
  final memoryBytes = cacheManager.getMemoryCacheBytes();
  final memoryMaxBytes = cacheManager.getMemoryCacheMaxBytes();
  final diskBytes = await cacheManager.getDiskCacheBytes();

  print('Memory cache: $memoryBytes B');
  print('Memory cache max: $memoryMaxBytes B');
  print('Disk cache: $diskBytes B');
}

Future<void> clearAllCache() async {
  await XNZCacheManager().clearAll();
}

Future<void> clearUnusedDiskCache() async {
  // Delete disk cache entries not used for 30 days.
  final deleted = await XNZCacheManager().clearUnusedDiskCache(
    const Duration(days: 30),
  );
  print('Deleted disk cache files: $deleted');
}

Platform Notes #

  • Web supports XNZNetworkImage, XNZMemoryImage, XNZAssetImage, and XNZAnimatedImage.
  • Web enables memory cache only (disk cache is disabled).
  • Web memory cache defaults to 48MB (native platforms default to 300MB).
  • XNZFileImage / XNZFileImageProvider are not supported on Web and throw UnsupportedError.

Run Example #

Minimal pub example:

flutter run -t example/main.dart

More complete demo apps are under:

  • examples/example_bitmap
  • examples/example_bitmap_svg
  • examples/example_bitmap_avif
  • examples/example_bitmap_svg_avif

概览 #

  • xnz_image:对外主 API(XNZNetworkImageXNZMemoryImageXNZFileImageXNZAssetImageXNZCacheManager 等)
  • xnz_image_core:内部基础能力(缓存、下载、扩展机制)
  • xnz_image_svg:SVG 格式支持扩展
  • xnz_image_avif:AVIF 格式支持扩展

安装 #

1) 基础能力 #

dependencies:
  xnz_image: ^0.2.2

2) 可选扩展(按需) #

dependencies:
  xnz_image: ^0.2.2
  xnz_image_svg: ^0.2.2
  xnz_image_avif: ^0.2.2

在本仓库联调时可使用 path 依赖。

扩展注册 #

import 'package:flutter/widgets.dart';
import 'package:xnz_image/xnz_image.dart';
import 'package:xnz_image_svg/xnz_image_svg.dart';
import 'package:xnz_image_avif/xnz_image_avif.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  XNZImageLogs.showLogs = true;
  XNZImageMemoryObserver().init();

  XNZImage.support(XNZImageSvg());
  XNZImage.support(XNZImageAvif());

  runApp(const MyApp());
}

支持格式 #

  • 默认(只引入 xnz_image):pngjpgjpeggifwebpbmp
  • 引入并注册 xnz_image_svg 后:svgsvgz
  • 引入并注册 xnz_image_avif 后:avifavifs(支持 AVIF 动图时长覆盖参数)

基础组件示例 #

网络图片 #

XNZNetworkImage(
  imageUrl: 'https://picsum.photos/800/480',
  width: 300,
  height: 180,
  fit: BoxFit.cover,
)

内存图片 #

XNZMemoryImage(
  bytes: yourBytes,
  width: 300,
  height: 180,
  fit: BoxFit.cover,
)

文件图片 #

XNZFileImage(
  file: File('/path/to/local/image.avif'),
  width: 300,
  height: 180,
  fit: BoxFit.cover,
)

Asset 图片 #

XNZAssetImage(
  assetName: 'assets/images/banner.avif',
  width: 300,
  height: 180,
  fit: BoxFit.cover,
)

与 Flutter Image 组合 #

Image(
  image: XNZNetworkImageProvider('https://picsum.photos/800/480'),
  width: 300,
  height: 180,
  fit: BoxFit.cover,
)

动画播放组件 #

XNZAnimatedImage 支持帧解码播放,适用于 GIF / Animated WebP / APNG。 注册 AVIF 扩展后,也可自动处理 AVIF 动图。

能力概览 #

  • 精准 UI 同步:positionprogressframeIndex
  • 播放控制:playpauseresumereplay
  • 回调:onLoadedonCompleted
  • 循环开关:loop
  • 异常兜底:errorBuilder

2026-05-11 维护性更新 #

  • 已优化 memory 场景的动图缓存 key:为 bytes 指纹增加 identity 级缓存,避免频繁全量字节哈希带来的重复 CPU 开销。
  • 已将 XNZAnimatedImage 的加载/解码/缓存 key/provider 上下文等能力拆分到 lib/src/animated/ 子模块,降低单文件职责复杂度。
  • 已抽取四类基础图片组件的统一 resolve/render helper(XNZAssetImageXNZMemoryImageXNZFileImageXNZNetworkImage),减少重复模板代码并提升一致性。
  • 对外 API 与使用方式保持兼容,无需业务侧改造。

用法示例 #

final controller = XNZAnimatedImageController();

XNZAnimatedImage(
  image: XNZNetworkImageProvider('https://example.com/demo.gif'),
  controller: controller,
  autoPlay: true,
  loop: true,
  fit: BoxFit.contain,
  onLoaded: (duration, fps, frameCount) {
    debugPrint('duration=$duration fps=$fps frames=$frameCount');
  },
  onCompleted: (completedLoops) {
    debugPrint('completedLoops=$completedLoops');
  },
  loadingBuilder: (_) => const Center(child: CircularProgressIndicator()),
  errorBuilder: (context, error, stackTrace) {
    return const Center(child: Text('Animated image load failed'));
  },
)

统一渲染回调(renderBuilder#

使用 renderBuilder 可以统一包装默认渲染结果:

XNZNetworkImage(
  imageUrl: url,
  renderBuilder: (context, child) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(12),
      child: child,
    );
  },
)

renderBuilder 返回 null 时,会回退到默认渲染。

缓存管理 #

import 'package:xnz_image/xnz_image.dart';

Future<void> printCacheUsage() async {
  final cacheManager = XNZCacheManager();
  final memoryBytes = cacheManager.getMemoryCacheBytes();
  final memoryMaxBytes = cacheManager.getMemoryCacheMaxBytes();
  final diskBytes = await cacheManager.getDiskCacheBytes();

  print('Memory cache: $memoryBytes B');
  print('Memory cache max: $memoryMaxBytes B');
  print('Disk cache: $diskBytes B');
}

Future<void> clearAllCache() async {
  await XNZCacheManager().clearAll();
}

Future<void> clearUnusedDiskCache() async {
  // 删除 30 天未命中的磁盘缓存。
  final deleted = await XNZCacheManager().clearUnusedDiskCache(
    const Duration(days: 30),
  );
  print('Deleted disk cache files: $deleted');
}

平台说明 #

  • Web 平台支持 XNZNetworkImageXNZMemoryImageXNZAssetImageXNZAnimatedImage
  • Web 平台仅启用内存缓存,不启用磁盘缓存。
  • Web 内存缓存默认上限 48MB(非 Web 平台默认 300MB)。
  • XNZFileImage / XNZFileImageProvider 在 Web 上不支持,调用时会抛出 UnsupportedError

运行示例 #

最小示例:

flutter run -t example/main.dart

完整演示项目在:

  • examples/example_bitmap
  • examples/example_bitmap_svg
  • examples/example_bitmap_avif
  • examples/example_bitmap_svg_avif
1
likes
0
points
59
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter image component for unified loading, downloading, and caching of network/memory/file/asset images, with extensible SVG/AVIF format support.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, xnz_image_core

More

Packages that depend on xnz_image