Flutter图像模糊预览插件fast_blurhash的使用

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

Flutter图像模糊预览插件 fast_blurhash 的使用

fast_blurhash 是一个利用 Rust 解码 BlurHash 并使用 Dart FFI 调用这些函数的 Dart 包。相比常见的 Dart 实现,它平均快 20 倍以上,并且可以在发布模式下通过运行 benchmarks.dart 演示来测试其性能。

状态

  • 使用实验性 API,未来可能会有所更改。
  • 第一次调用需要更长时间,因此添加了一个设置函数进行预热调用。
  • 仅在 iOS 和 MacOS 上的发布模式中进行了测试。
  • 发布模式和调试模式之间的性能差异显著,请勿依赖调试模式的结果。

项目结构

  • rust: 包含 Rust 源代码。
  • lib: 包含定义插件 API 的 Dart 代码,并使用 dart:ffi 调用本地代码。

性能基准测试

为了在发布模式下测试包的性能,可以运行 benchmarks.dart 演示:

flutter run -t lib/benchmarks.dart --release

iPhone 15 Pro 示例截图

iPhone 15 Pro

M1 MacBook Pro 示例截图

M1 MacBook Pro

示例 Demo

以下是完整的示例代码,展示了如何使用 fast_blurhash 插件:

import 'dart:typed_data';
import 'package:fast_blurhash/fast_blurhash.dart';
import 'package:flutter/material.dart';

void main() {
  setup(); // 初始化预热调用
  runApp(const BlurHashDemo());
}

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

  [@override](/user/override)
  State<BlurHashDemo> createState() => _BlurHashDemoState();
}

class _BlurHashDemoState extends State<BlurHashDemo> {
  final images = [
    "https://i.imgur.com/fU8vqCi.jpeg",
    "https://i.imgur.com/2CXbtO9.jpeg",
    "https://i.imgur.com/54sDohv.jpeg",
  ];

  final hashes = [
    "THEC,t~qWGb=IUxI%ejEIBR~xuaf",
    "TKLpT@?w=V_3RkH=10IU,nT1NGn4",
    "TgDSt8kDWV~qt7WV_3s:ay?bofj@",
  ];

  bool useAsync = false;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('BlurHash Demo'),
          actions: [
            Switch(
              value: useAsync,
              onChanged: (value) {
                setState(() {
                  useAsync = value;
                });
              },
            ),
            Padding(
              padding: const EdgeInsets.only(right: 16.0),
              child: Center(
                child: Text(useAsync ? 'Async' : 'Sync'),
              ),
            ),
          ],
        ),
        body: PageView.builder(
          scrollDirection: Axis.vertical,
          itemCount: images.length,
          itemBuilder: (BuildContext context, int index) {
            if (useAsync) {
              return FastBlurhashWidgetBuilder(blurhashString: hashes[index]);
            }
            return SizedBox.expand(
              child: FadeInImage.memoryNetwork(
                fit: BoxFit.cover,
                placeholder: decodeBlurhash(blurhashString: hashes[index]),
                fadeInDuration: const Duration(seconds: 2),
                fadeOutDuration: const Duration(seconds: 2),
                image: images[index],
              ),
            );
          },
        ),
      ),
    );
  }
}

class FastBlurhashWidgetBuilder extends StatefulWidget {
  const FastBlurhashWidgetBuilder({
    super.key,
    required this.blurhashString,
    this.height = 32,
    this.width = 32,
    this.punch = 1.0,
    this.enableCache = true,
    this.child,
  });

  final String blurhashString;
  final int height;
  final int width;
  final double punch;
  final bool enableCache;
  final Widget? child;

  [@override](/user/override)
  State<FastBlurhashWidgetBuilder> createState() =>
      _FastBlurhashWidgetBuilderState();
}

class _FastBlurhashWidgetBuilderState extends State<FastBlurhashWidgetBuilder> {
  late Future<Uint8List> _blurhashFuture;

  [@override](/user/override)
  void initState() {
    super.initState();
    _blurhashFuture = decodeBlurhashIsolate(
      blurhashString: widget.blurhashString,
      height: widget.height,
      width: widget.width,
      punch: widget.punch,
      enableCache: widget.enableCache,
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return FutureBuilder<Uint8List>(
      future: _blurhashFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done &&
            snapshot.hasData) {
          return Stack(
            children: [
              Image.memory(
                snapshot.data!,
                fit: BoxFit.cover,
                width: double.infinity,
                height: double.infinity,
              ),
              if (widget.child != null) widget.child!,
            ],
          );
        } else {
          return widget.child ?? Container(color: Colors.transparent);
        }
      },
    );
  }
}

更多关于Flutter图像模糊预览插件fast_blurhash的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图像模糊预览插件fast_blurhash的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用fast_blurhash插件来实现图像模糊预览的示例代码。fast_blurhash是一个用于生成和显示Blurhash图像的插件,Blurhash是一种用于快速生成和渲染模糊图像的技术,常用于图像加载时的占位符。

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

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

然后,运行flutter pub get来安装依赖。

接下来是一个完整的Flutter应用程序示例,展示了如何使用fast_blurhash来显示Blurhash图像:

import 'package:flutter/material.dart';
import 'package:fast_blurhash/fast_blurhash.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Fast Blurhash Example'),
        ),
        body: Center(
          child: BlurhashExample(),
        ),
      ),
    );
  }
}

class BlurhashExample extends StatefulWidget {
  @override
  _BlurhashExampleState createState() => _BlurhashExampleState();
}

class _BlurhashExampleState extends State<BlurhashExample> {
  String blurHashString = "LDBBARNB+w0yxpy1+VmUXgp9uQ0D";  // 示例Blurhash字符串

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        BlurhashImage(
          blurHash: blurHashString,
          image: NetworkImage('https://example.com/path/to/your/image.jpg'),  // 替换为你的图像URL
          width: 300,
          height: 200,
          placeholderWidget: Container(
            color: Colors.grey.shade200,
          ),
        ),
        SizedBox(height: 20),
        Text('Blurhash: $blurHashString'),
      ],
    );
  }
}

// 自定义BlurhashImage组件,用于显示Blurhash占位符和加载真实图像
class BlurhashImage extends StatefulWidget {
  final String blurHash;
  final ImageProvider image;
  final double width;
  final double height;
  final Widget placeholderWidget;

  BlurhashImage({
    required this.blurHash,
    required this.image,
    required this.width,
    required this.height,
    this.placeholderWidget = const SizedBox.shrink(),
  });

  @override
  _BlurhashImageState createState() => _BlurhashImageState();
}

class _BlurhashImageState extends State<BlurhashImage> {
  bool isImageLoaded = false;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        if (!isImageLoaded)
          Blurhash(
            hash: widget.blurHash,
            width: widget.width,
            height: widget.height,
            child: widget.placeholderWidget,
          ),
        Positioned.fill(
          child: Image(
            image: widget.image,
            width: widget.width,
            height: widget.height,
            fit: BoxFit.cover,
            loadingBuilder: (BuildContext context, Widget child, ImageInfo? imageInfo, Widget? placeholder) {
              if (imageInfo == null) {
                return placeholder;
              }
              setState(() {
                isImageLoaded = true;
              });
              return child;
            },
          ),
        ),
      ],
    );
  }
}

在这个示例中,我们定义了一个BlurhashImage组件,它首先显示一个Blurhash占位符,当真实图像加载完成时,将Blurhash占位符替换为真实图像。Blurhash组件用于渲染Blurhash字符串,而Image组件用于加载和显示真实图像。

请注意,你需要将示例Blurhash字符串和图像URL替换为你自己的值。

希望这个示例对你有所帮助!

回到顶部