cached_network_image_ce 4.12.0 copy "cached_network_image_ce: ^4.12.0" to clipboard
cached_network_image_ce: ^4.12.0 copied to clipboard

Community Edition Flutter library to load and cache network images. Can also be used with placeholder and error widgets.

example/lib/main.dart

import 'dart:io';

import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_blurhash/flutter_blurhash.dart';
import 'package:flutter_svg/flutter_svg.dart';

import 'benchmark_page.dart';

void main() {
  CachedNetworkImage.logLevel = CacheManagerLogLevel.debug;
  runApp(const ExampleApp());
}

class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'CachedNetworkImage CE Demo',
      theme: ThemeData(
        colorSchemeSeed: Colors.blue,
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 6,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('CachedNetworkImage CE'),
          bottom: const TabBar(
            isScrollable: true,
            tabs: [
              Tab(icon: Icon(Icons.image), text: 'Basic'),
              Tab(icon: Icon(Icons.list), text: 'List'),
              Tab(icon: Icon(Icons.grid_on), text: 'Grid'),
              Tab(icon: Icon(Icons.speed), text: 'Benchmark'),
              Tab(icon: Icon(Icons.download_done), text: 'PreCache'),
              Tab(icon: Icon(Icons.gif), text: 'Animate'),
            ],
          ),
        ),
        body: const TabBarView(
          children: [
            BasicContent(),
            ListContent(),
            GridContent(),
            BenchmarkContent(),
            PreCacheContent(),
            AnimateContent(),
          ],
        ),
      ),
    );
  }
}

/// Demonstrates a [StatelessWidget] containing [CachedNetworkImage]
class BasicContent extends StatelessWidget {
  const BasicContent({super.key});

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            // Image loaded with custom connection timeouts.
            _sizedContainer(
              CachedNetworkImage(
                cacheManager: DefaultCacheManager(
                  connectionParameters: ConnectionParameters(
                    connectionTimeout: const Duration(seconds: 10),
                    requestTimeout: const Duration(seconds: 30),
                  ),
                ),
                imageUrl:
                    'https://images.unsplash.com/photo-1522205408450-add114ad53fe?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=368f45b0888aeb0b7b08e3a1084d3ede&auto=format&fit=crop&w=1950&q=80',
                placeholder: (context, url) =>
                    const CircularProgressIndicator(),
                errorBuilder: (context, error, stackTrace) =>
                    const Icon(Icons.error),
              ),
            ),
            _blurHashImage(),
            _sizedContainer(
              CachedNetworkImage(
                imageUrl:
                    'https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg',
                placeholder: (context, url) =>
                    const CircularProgressIndicator(),
                unsupportedImageBuilder: (context, url, bytes) =>
                    SvgPicture.memory(
                  bytes,
                  fit: BoxFit.contain,
                ),
                errorBuilder: (context, error, stackTrace) =>
                    const Icon(Icons.error),
              ),
            ),
            _sizedContainer(
              const Image(
                width: double.infinity,
                fit: BoxFit.fitWidth,
                image: CachedNetworkImageProvider(
                  'https://images.unsplash.com/photo-1614517453351-6c1522fc7a56',
                ),
              ),
              width: double.infinity,
              height: 200,
            ),
            _sizedContainer(
              CachedNetworkImage(
                progressIndicatorBuilder: (context, url, progress) => Center(
                  child: CircularProgressIndicator(
                    value: progress.progress,
                  ),
                ),
                imageUrl:
                    'https://images.unsplash.com/photo-1532264523420-881a47db012d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9',
              ),
            ),
            _sizedContainer(
              CachedNetworkImage(
                placeholder: (context, url) =>
                    const CircularProgressIndicator(),
                imageUrl:
                    'https://plus.unsplash.com/premium_photo-1695566086196-1cdadbaa1988?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
              ),
            ),
            _sizedContainer(
              CachedNetworkImage(
                imageUrl:
                    'https://images.unsplash.com/photo-1644588815329-4705c4418d38?q=80&w=1473&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
                imageBuilder: (context, imageProvider) => Container(
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: imageProvider,
                      fit: BoxFit.cover,
                      colorFilter: const ColorFilter.mode(
                        Colors.red,
                        BlendMode.colorBurn,
                      ),
                    ),
                  ),
                ),
                placeholder: (context, url) =>
                    const CircularProgressIndicator(),
                errorBuilder: (context, error, stackTrace) =>
                    const Icon(Icons.error),
              ),
            ),
            CachedNetworkImage(
              imageUrl:
                  'https://images.unsplash.com/photo-1565343486673-fbd3a3ce9331?q=80&w=1471&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
              placeholder: (context, url) => const CircleAvatar(
                backgroundColor: Colors.amber,
                radius: 150,
              ),
              imageBuilder: (context, image) => CircleAvatar(
                backgroundImage: image,
                radius: 150,
              ),
            ),
            _sizedContainer(
              CachedNetworkImage(
                errorBuilder: (context, error, stackTrace) =>
                    const Icon(Icons.error),
                placeholder: (context, url) =>
                    const CircularProgressIndicator(),
                imageUrl: 'not a valid uri',
              ),
            ),
            _sizedContainer(
              CachedNetworkImage(
                imageUrl: 'not a uri at all',
                placeholder: (context, url) =>
                    const CircularProgressIndicator(),
                errorBuilder: (context, error, stackTrace) =>
                    const Icon(Icons.error),
                errorListener: (e) {
                  if (e is SocketException) {
                    debugPrint(
                        'Error with ${e.address} and message ${e.message}');
                  } else {
                    debugPrint('Image Exception is: ${e.runtimeType}');
                  }
                },
              ),
            ),
            _sizedContainer(
              CachedNetworkImage(
                maxHeightDiskCache: 10,
                imageUrl:
                    'https://images.unsplash.com/photo-1706212074955-6045fce2521d?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
                placeholder: (context, url) =>
                    const CircularProgressIndicator(),
                errorBuilder: (context, error, stackTrace) =>
                    const Icon(Icons.error),
                fadeInDuration: const Duration(seconds: 3),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _blurHashImage() {
    return SizedBox(
      width: double.infinity,
      child: CachedNetworkImage(
        placeholder: (context, url) => const AspectRatio(
          aspectRatio: 1.6,
          child: BlurHash(hash: 'LEHV6nWB2yk8pyo0adR*.7kCMdnj'),
        ),
        imageUrl: 'https://blurha.sh/12c2aca29ea896a628be.jpg',
        fit: BoxFit.cover,
      ),
    );
  }

  Widget _sizedContainer(Widget child,
      {double width = double.infinity, double height = 250}) {
    return SizedBox(
      width: width,
      height: height,
      child: Center(child: child),
    );
  }
}

/// Demonstrates a [ListView] containing [CachedNetworkImage]
class ListContent extends StatelessWidget {
  const ListContent({super.key});

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: (BuildContext context, int index) => Card(
        child: Column(
          children: <Widget>[
            CachedNetworkImage(
              imageUrl: 'https://loremflickr.com/320/240/music?lock=$index',
              placeholder: (BuildContext context, String url) => Container(
                width: 320,
                height: 240,
                color: Colors.purple,
              ),
            ),
          ],
        ),
      ),
      itemCount: 250,
    );
  }
}

/// Demonstrates a [GridView] containing [CachedNetworkImage]
class GridContent extends StatelessWidget {
  const GridContent({super.key});

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      itemCount: 250,
      gridDelegate:
          const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
      itemBuilder: (BuildContext context, int index) => CachedNetworkImage(
        imageUrl: 'https://loremflickr.com/100/100/music?lock=$index',
        placeholder: _loader,
        errorBuilder: _error,
      ),
    );
  }

  Widget _loader(BuildContext context, String url) {
    return const Center(child: CircularProgressIndicator());
  }

  Widget _error(BuildContext context, Object error, StackTrace? stackTrace) {
    return const Center(child: Icon(Icons.error));
  }
}

class PreCacheContent extends StatefulWidget {
  const PreCacheContent({super.key});

  @override
  State<PreCacheContent> createState() => _PreCacheContentState();
}

class _PreCacheContentState extends State<PreCacheContent> {
  static const _imageUrl =
      'https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=800';
  bool _loading = false;
  bool _cached = false;

  Future<void> _preCache() async {
    setState(() => _loading = true);
    try {
      await CachedNetworkImage.preCache(imageUrl: _imageUrl);
      if (mounted) setState(() => _cached = true);
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('PreCache failed: $e')),
        );
      }
    } finally {
      if (mounted) setState(() => _loading = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          if (!_cached)
            ElevatedButton.icon(
              onPressed: _loading ? null : _preCache,
              icon: _loading
                  ? const SizedBox.square(
                      dimension: 16,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : const Icon(Icons.download),
              label: Text(_loading ? 'Pre-caching...' : 'Pre-cache image'),
            ),
          if (_cached) ...[
            const Text('Image cached! Displaying from cache:'),
            const SizedBox(height: 16),
            SizedBox(
              height: 300,
              child: CachedNetworkImage(
                imageUrl: _imageUrl,
                placeholder: (context, url) =>
                    const CircularProgressIndicator(),
              ),
            ),
          ],
        ],
      ),
    );
  }
}

/// Demonstrates the two ways to stop an animated image.
///
/// [CachedNetworkImage.animate] is part of the image provider key, so toggling
/// it resolves a different image stream: the image goes blank while that
/// stream resolves, and which frame it comes back on depends on whether its
/// key is still held by the `ImageCache` — switching animation back on is
/// likely to resume where it left off rather than restart. [TickerMode]
/// pauses and resumes the running animation in place, with no key change.
///
/// Both images ask for [ImageRenderMethodForWeb.HttpGet] because the web
/// default, `HtmlImage`, decodes through an `<img>` element whose codec
/// reports a single frame. Animated images never play on that path, so
/// there would be nothing to stop. The option is ignored off the web.
class AnimateContent extends StatefulWidget {
  const AnimateContent({super.key});

  @override
  State<AnimateContent> createState() => _AnimateContentState();
}

class _AnimateContentState extends State<AnimateContent> {
  static const _gifUrl =
      'https://upload.wikimedia.org/wikipedia/commons/d/d3/Newtons_cradle_animation_book_2.gif';

  bool _animate = true;
  bool _ticking = true;

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: [
          SwitchListTile(
            title: const Text('animate'),
            subtitle: const Text('Freezes on the first frame. Switching back '
                'on resolves a different provider key.'),
            value: _animate,
            onChanged: (value) => setState(() => _animate = value),
          ),
          SizedBox(
            height: 200,
            child: CachedNetworkImage(
              imageUrl: _gifUrl,
              // Both demos load the same URL, and everything the provider
              // compares is otherwise equal, so without distinct cache keys
              // they would share one completer and neither switch would
              // demonstrate anything.
              cacheKey: '\$_gifUrl#animate',
              animate: _animate,
              imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
              placeholder: (context, url) => const CircularProgressIndicator(),
              errorBuilder: (context, error, stackTrace) =>
                  const Icon(Icons.error),
            ),
          ),
          const Divider(height: 32),
          SwitchListTile(
            title: const Text('TickerMode'),
            subtitle: const Text('Pauses and resumes in place. Also what '
                'MediaQueryData.disableAnimations uses.'),
            value: _ticking,
            onChanged: (value) => setState(() => _ticking = value),
          ),
          SizedBox(
            height: 200,
            child: TickerMode(
              enabled: _ticking,
              child: CachedNetworkImage(
                imageUrl: _gifUrl,
                cacheKey: '\$_gifUrl#ticker',
                imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
                placeholder: (context, url) =>
                    const CircularProgressIndicator(),
                errorBuilder: (context, error, stackTrace) =>
                    const Icon(Icons.error),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
99
likes
160
points
85.8k
downloads

Documentation

API reference

Publisher

verified publishererengun.dev

Weekly Downloads

Community Edition Flutter library to load and cache network images. Can also be used with placeholder and error widgets.

Homepage
Repository (GitHub)
View/report issues
Contributing

Topics

#cache #image #network-image

License

MIT (license)

Dependencies

cached_network_image_platform_interface_ce, cached_network_image_web_ce, crypto, file, flutter, hive_ce, http, meta, octo_image, path, path_provider

More

Packages that depend on cached_network_image_ce