Flutter网络图片保存到文件插件network_to_file_image的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter网络图片保存到文件插件network_to_file_image的使用

network_to_file_image 是一个用于将网络图片下载并保存到本地文件系统的Flutter插件。它结合了 NetworkImageFileImage 的功能,实现了以下目标:

  • 从URL下载图片一次。
  • 将图片保存到本地文件系统。
  • 之后使用保存在文件系统的图片。

更多细节

给定一个文件和图片的URL,该插件首先尝试从本地文件读取图片。如果图片尚未作为本地文件存在,则从网络中获取给定的URL,并将其与给定的比例关联,然后保存到本地文件。无论服务器的缓存头如何,图片都会被缓存。

注意事项

  • 如果提供的URL为空或null,NetworkToFileImage 将默认为 FileImage,即只从本地文件读取图片,不会尝试从网络下载。
  • 如果提供的文件为null,NetworkToFileImage 将默认为 NetworkImage,即只从网络下载图片,不会保存到本地。

使用插件

引入依赖

在你的 pubspec.yaml 文件中添加 path_provider 依赖:

dependencies:
  path_provider: ^2.1.1 

创建文件

使用 path_provider 创建一个 File 对象:

import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;

Future<File> file(String filename) async {
  Directory dir = await getApplicationDocumentsDirectory();
  String pathName = p.join(dir.path, filename);
  return File(pathName);
}

var myFile = await file("myFileName.png");

创建图片

使用 NetworkToFileImage 创建图片:

Image(image: 
   NetworkToFileImage(
      url: "https://example.com/someFile.png", 
      file: myFile,
   )
)

你可以通过设置 debug: true 来打印控制台日志,显示图片是从文件读取还是从网络获取:

Image(image: 
   NetworkToFileImage(
      url: "https://example.com/someFile.png", 
      file: myFile, 
      debug: true,
   )
)

示例代码

下面是一个完整的示例代码,展示了如何使用 network_to_file_image 插件:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:network_to_file_image/network_to_file_image.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';

late Directory _appDocsDir;

void main() async {
  // 确保初始化Flutter绑定
  WidgetsFlutterBinding.ensureInitialized();
  _appDocsDir = await getApplicationDocumentsDirectory();

  runApp(MaterialApp(home: Demo()));
}

File fileFromDocsDir(String filename) {
  String pathName = p.join(_appDocsDir.path, filename);
  return File(pathName);
}

class Demo extends StatefulWidget {
  @override
  State<Demo> createState() => _DemoState();
}

class _DemoState extends State<Demo> {
  int count = 0;

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('NetworkToFileImage example')),
        body: Padding(
          padding: const EdgeInsets.all(30.0),
          child: SingleChildScrollView(
            child: Column(
              children: [
                _image(),
                const SizedBox(height: 30),
                _button(),
                SizedBox(height: 30),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('1. This prints debug messages to the console:'),
                    SizedBox(height: 6),
                    Text('NetworkToFileImage(... debug: true);', style: TextStyle(fontSize: 10)),
                    SizedBox(height: 35),
                    //
                    Text('2. Rebuilding or hot-reloading should not read the image again, '
                        'as the image is cached.'),
                    SizedBox(height: 35),
                    //
                    Text('3. Restarting the app should, however, say something like:'),
                    SizedBox(height: 6),
                    Text('Reading image file: /data/user/0/xxx/app_flutter/flutter.png',
                        style: TextStyle(fontSize: 10)),
                    SizedBox(height: 35),
                    //
                    Text('4. Changing the filename here from:'),
                    SizedBox(height: 6),
                    Text('file: fileFromDocsDir("flutter.png")', style: TextStyle(fontSize: 10)),
                    SizedBox(height: 12),
                    Text('To:'),
                    SizedBox(height: 6),
                    Text('file: fileFromDocsDir("flutterX.png")', style: TextStyle(fontSize: 10)),
                    SizedBox(height: 10),
                    Text('And restarting the app, should print this to the console:'),
                    SizedBox(height: 6),
                    Text('Fetching image from: https://.../Google-flutter-logo.png',
                        style: TextStyle(fontSize: 10)),
                    Text('Saving image to file: /data/user/0/xxx/app_flutter/flutterX.png',
                        style: TextStyle(fontSize: 10)),
                  ],
                ),
              ],
            ),
          ),
        ),
      );

  Widget _image() {
    return Image(
      key: ValueKey(count),
      image: NetworkToFileImage(
        url: "https://upload.wikimedia.org/wikipedia/commons/1/17/Google-flutter-logo.png",
        file: fileFromDocsDir("flutter.png"),
        debug: true,
      ),
      errorBuilder: (context, error, stackTrace) {
        return Center(child: Text('Download image failed: $error.', textAlign: TextAlign.center));
      },
    );
  }

  Widget _button() {
    return ElevatedButton(
      onPressed: () {
        setState(() {
          count++;
        });
      },
      child: Text('Rebuild image widget'),
    );
  }
}

重要提示

确保你想要保存图片的目录已经存在于本地磁盘中。否则,图片将无法保存。

Canvas支持

你还可以使用 ImageForCanvas 类将图片加载到 CustomPainterCanvas 对象中。例如:

var imageForCanvas = ImageForCanvas<User>(
  imageProviderSupplier: (User user) => NetworkToFileImage(file: user.file, url: user.url),
  keySupplier: (User user) => user.filename,
  loadCallback: (image, obj, key) => setState((){}),
);

// 当图片正在下载时,这将返回null
var myImage = imageForCanvas.image(user);

if (myImage != null) {
  canvas.drawImage(myImage, ...);
}

测试

你可以设置模拟文件(本地和网络)。请参阅以下方法:

  • setMockFile(File file, Uint8List bytes)
  • setMockUrl(String url, Uint8List bytes)
  • clearMocks()
  • clearMockFiles()
  • clearMockUrls()

你可以通过调用 NetworkToFileImage.startHttpOverride() 方法来覆盖默认的Dart http方法,使这些URL对其他 ImageProviders 可见。停止HTTP覆盖可以通过调用 NetworkToFileImage.stopHttpOverride() 方法实现。

希望这个指南对你有所帮助!如果你有任何问题,请随时提问。


更多关于Flutter网络图片保存到文件插件network_to_file_image的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter网络图片保存到文件插件network_to_file_image的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,我可以为你提供一个关于如何使用 network_to_file_image 插件将 Flutter 中的网络图片保存到文件的代码示例。network_to_file_image 插件允许你轻松地将网络图片缓存到本地文件中,并在之后的应用程序中重复使用这些缓存的图片。

首先,你需要在你的 pubspec.yaml 文件中添加 network_to_file_image 依赖:

dependencies:
  flutter:
    sdk: flutter
  network_to_file_image: ^x.y.z  # 请将 x.y.z 替换为最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来是一个简单的示例,展示了如何使用 network_to_file_image 将网络图片保存到本地文件,并在 Image.file 中使用这些缓存的图片:

import 'package:flutter/material.dart';
import 'package:network_to_file_image/network_to_file_image.dart';
import 'dart:io';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Network to File Image Example'),
        ),
        body: Center(
          child: NetworkToFileImageExample(),
        ),
      ),
    );
  }
}

class NetworkToFileImageExample extends StatefulWidget {
  @override
  _NetworkToFileImageExampleState createState() => _NetworkToFileImageExampleState();
}

class _NetworkToFileImageExampleState extends State<NetworkToFileImageExample> {
  File? _cachedImageFile;

  @override
  void initState() {
    super.initState();
    _cacheImage();
  }

  Future<void> _cacheImage() async {
    final imageUrl = 'https://example.com/path/to/your/image.jpg'; // 替换为你的图片URL
    final directory = (await getApplicationDocumentsDirectory()).path;
    final file = File('$directory/cached_image.jpg');

    // 使用 NetworkToFileImage 缓存图片
    await NetworkToFileImage().downloadFile(imageUrl, file.path);

    setState(() {
      _cachedImageFile = file;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        if (_cachedImageFile != null)
          Image.file(_cachedImageFile!),
        else
          CircularProgressIndicator(),
        SizedBox(height: 20),
        ElevatedButton(
          onPressed: () async {
            // 你可以在这里再次调用 _cacheImage() 方法来重新缓存图片,或者做其他操作
            ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Button pressed')));
          },
          child: Text('Press me'),
        ),
      ],
    );
  }
}

在这个示例中:

  1. 我们首先定义了一个 MyApp 应用程序,其中包含了一个 Scaffold 和一个居中的 NetworkToFileImageExample 小部件。
  2. NetworkToFileImageExample 是一个有状态的小部件,用于管理缓存的图片文件。
  3. initState 方法中,我们调用 _cacheImage 方法来缓存网络图片。
  4. _cacheImage 方法使用 NetworkToFileImage().downloadFile 方法将网络图片下载并缓存到本地文件中。
  5. build 方法中,我们检查 _cachedImageFile 是否为空。如果不为空,则显示缓存的图片;否则,显示一个 CircularProgressIndicator
  6. 我们还添加了一个按钮,用于演示其他可能的交互操作。

这个示例展示了如何使用 network_to_file_image 插件来缓存网络图片并在 Flutter 应用中使用它们。你可以根据需要进行扩展和修改。

回到顶部