Flutter图片处理或加载插件app_image的使用

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

Flutter图片处理或加载插件app_image的使用

app_image 是一个多功能的Flutter包,旨在简化应用程序中的图像处理。它提供了一个高度可定制的 AppImage 小部件,支持各种图像来源,包括网络URL、资产路径、文件路径和内存图像。此包具有淡入动画、自定义占位符和错误小部件、全屏图像查看、SVG支持和预缓存功能。

Sample

特性

  • 淡入动画:应用平滑的淡入效果,并可自定义持续时间和曲线以增强视觉体验。
  • 占位符和错误小部件:在图像加载或出现错误时显示自定义的占位符和错误小部件。
  • 全屏图像查看器:通过简单的点击手势启用全屏查看图像。
  • SVG支持:无缝处理来自网络、资产和文件源的SVG图像。
  • 预缓存:预缓存图像以提高加载性能并提供更流畅的用户体验。
  • 自动图像提供者选择:根据图像来源自动确定适当的图像提供者,如有需要可以显式定义 ImgProvider

安装

将以下内容添加到您的 pubspec.yaml 文件中:

dependencies:
  app_image: ^1.0.9

然后运行 flutter pub get 来安装该包。

使用方法

基本用法
import 'package:app_image/app_image.dart';
import 'package:flutter/material.dart';

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: AppImage(
            image: 'https://example.com/image.jpg', // 图像来源
            placeHolderWidget: CircularProgressIndicator(), // 加载时的占位符
            errorWidget: Icon(Icons.error), // 错误时的小部件
            fadeInDuration: Duration(milliseconds: 300), // 淡入动画持续时间
            fadeInCurve: Curves.easeIn, // 淡入动画曲线
            enableFullScreenView: true, // 启用全屏查看
          ),
        ),
      ),
    );
  }
}
全屏查看器

启用图像的全屏查看:

AppImage(
  image: 'https://example.com/image.jpg',
  enableFullScreenView: true,
  allImages: [
    'https://example.com/image1.jpg',
    'https://example.com/image2.jpg',
    'https://example.com/image3.jpg',
  ], // 所有可用的图像
);
自定义占位符和错误小部件

您可以自定义占位符和错误小部件:

AppImage(
  image: 'https://example.com/image.jpg',
  placeHolderWidget: CircularProgressIndicator(), // 自定义占位符
  errorWidget: Icon(Icons.broken_image), // 自定义错误小部件
);
SVG支持

显示SVG图像:

AppImage(
  image: 'assets/image.svg', // SVG图像来源
);

示例

以下是完整的示例demo,展示了如何使用 app_image 包:

import 'package:app_image/app_image.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'AppImage Package Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final networkImages = [
    'https://picsum.photos/500?random=1',
    'https://picsum.photos/500?random=2',
    'https://picsum.photos/500?random=3',
    'https://picsum.photos/500?random=4',
  ];

  String assetImage = 'assets/elriz-logo.jpg';
  dynamic fileImage;
  Uint8List? memoryImage;
  String svgImageNetwork = 'https://svgur.com/i/18Q4.svg';
  String? svgImageFile;
  String svgImageAsset = 'assets/svg-sample.svg';

  Future<void> loadImage() async {
    // 示例:从资源加载图像并将其转换为Uint8List
    final ByteData data = await rootBundle.load(assetImage);
    memoryImage = data.buffer.asUint8List();
    setState(() {});
  }

  [@override](/user/override)
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      loadImage();
    });
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('AppImage Package Example'),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(18.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            defaultAppImage(),
            const SizedBox(height: 24),
            customAppImage(),
            const SizedBox(height: 24),
            allSupportedImgProviders()
          ],
        ),
      ),
    );
  }

  Widget defaultAppImage() {
    return Wrap(
      spacing: 18,
      runSpacing: 18,
      children: [
        Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(
              'Default',
              style: Theme.of(context).textTheme.titleSmall,
            ),
            const SizedBox(height: 8),
            const AppImage(
              image: 'https://picsum.photos/500?random=1', // 随机图像
              width: 200,
              height: 200,
              enableFullScreenView: true, // 启用全屏查看
            ),
          ],
        ),
        Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(
              'Default Error Placeholder',
              style: Theme.of(context).textTheme.titleSmall,
            ),
            const SizedBox(height: 8),
            AppImage(
              image: '', // 空图像源会触发错误小部件
              width: 200,
              height: 200,
              backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
            ),
          ],
        ),
      ],
    );
  }

  Widget customAppImage() {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Text(
          'Custom',
          style: Theme.of(context).textTheme.titleSmall,
        ),
        const SizedBox(height: 8),
        Wrap(
          spacing: 18,
          runSpacing: 18,
          children: [
            AppImage(
              image: networkImages[0],
              allImages: networkImages,
              width: 200,
              height: 200,
              backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
              borderRadius: BorderRadius.circular(18),
              enableFullScreenView: true,
            ),
            AppImage(
              image: networkImages[1],
              allImages: networkImages,
              width: 200,
              height: 200,
              backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
              border: Border.all(
                  width: 8, color: Theme.of(context).colorScheme.primary),
              borderRadius: BorderRadius.circular(18),
              enableFullScreenView: true,
            ),
            AppImage(
              image: networkImages[2],
              allImages: networkImages,
              width: 300,
              height: 200,
              backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
              border: Border(
                left: BorderSide(
                    width: 8, color: Theme.of(context).colorScheme.primary),
                right: BorderSide(
                    width: 8, color: Theme.of(context).colorScheme.primary),
              ),
              borderRadius: BorderRadius.circular(18),
              enableFullScreenView: true,
            ),
            AppImage(
              image: networkImages[3],
              allImages: networkImages,
              width: 300,
              height: 200,
              backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
              border: Border(
                  left: BorderSide(
                      width: 8, color: Theme.of(context).colorScheme.primary)),
              borderRadius: const BorderRadius.only(topRight: Radius.circular(54)),
              enableFullScreenView: true,
              fadeInCurve: Curves.easeInOut,
              fadeInDuration: const Duration(seconds: 3),
            ),
          ],
        ),
      ],
    );
  }

  Widget allSupportedImgProviders() {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Text(
          'All Supported Providers',
          style: Theme.of(context).textTheme.titleSmall,
        ),
        const SizedBox(height: 8),
        Wrap(
          spacing: 18,
          runSpacing: 18,
          children: [
            imageWidget('Network', networkImages.first),
            pickFileImageWidget('File', fileImage),
            imageWidget('Asset', assetImage),
            imageWidget('Memory', memoryImage),
            imageWidget('SVG Image Network', svgImageNetwork),
            pickSvgFileImageWidget('SVG Image File', svgImageFile),
            imageWidget('SVG Image Asset', svgImageAsset),
          ],
        ),
      ],
    );
  }

  Widget pickFileImageWidget(String title, dynamic image) {
    if (image == null) {
      return GestureDetector(
        onTap: () async {
          FilePickerResult? result = await FilePicker.platform.pickFiles(
            type: FileType.custom,
            allowMultiple: false,
            allowedExtensions: ['jpg', 'jpeg', 'png'],
          );

          // 在Web平台上不支持文件图像
          // 使用字节代替
          fileImage = kIsWeb
              ? result?.files.firstOrNull?.bytes
              : result?.files.firstOrNull?.path;
          setState(() {});
        },
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              title,
              style: Theme.of(context).textTheme.bodyMedium,
            ),
            const SizedBox(height: 8),
            Container(
              width: 200,
              height: 200,
              alignment: Alignment.center,
              decoration: BoxDecoration(
                color: Theme.of(context).colorScheme.surfaceContainer,
                borderRadius: BorderRadius.circular(18),
              ),
              child: Text(
                'Pick File Image',
                style: Theme.of(context).textTheme.labelMedium,
              ),
            ),
          ],
        ),
      );
    }

    return imageWidget(title, image!);
  }

  Widget pickSvgFileImageWidget(String title, dynamic image) {
    if (image == null) {
      return GestureDetector(
        onTap: () async {
          FilePickerResult? result = await FilePicker.platform.pickFiles(
            type: FileType.custom,
            allowMultiple: false,
            allowedExtensions: ['svg'],
          );

          svgImageFile = result?.files.firstOrNull?.path;
          setState(() {});
        },
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              title,
              style: Theme.of(context).textTheme.bodyMedium,
            ),
            const SizedBox(height: 8),
            Container(
              width: 200,
              height: 200,
              alignment: Alignment.center,
              decoration: BoxDecoration(
                color: Theme.of(context).colorScheme.surfaceContainer,
                borderRadius: BorderRadius.circular(18),
              ),
              child: Text(
                'Pick SVG Image',
                style: Theme.of(context).textTheme.labelMedium,
              ),
            ),
          ],
        ),
      );
    }

    return imageWidget(title, image!);
  }

  Widget imageWidget(String title, dynamic image) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          title,
          style: Theme.of(context).textTheme.bodyMedium,
        ),
        const SizedBox(height: 8),
        AppImage(
          image: image,
          width: 200,
          height: 200,
          backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
          borderRadius: BorderRadius.circular(18),
          enableFullScreenView: true,
        ),
      ],
    );
  }
}

更多关于Flutter图片处理或加载插件app_image的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图片处理或加载插件app_image的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter应用中使用app_image插件来处理或加载图片的示例代码。请注意,app_image并不是Flutter社区中广泛认知的一个标准插件,因此我将假设你指的是一个自定义的或者特定于某个项目的图片处理插件。为了演示目的,我将以一个假设的app_image插件为基础,展示如何加载和处理图片。

在实际应用中,你可能需要使用像cached_network_imageimage_pickerflutter_image_compress这样更流行的插件来处理图片。但为了满足你的要求,我将构建一个假设的app_image插件使用示例。

首先,确保在pubspec.yaml文件中添加app_image依赖(如果它存在的话;实际上,你可能需要替换为实际存在的插件):

dependencies:
  flutter:
    sdk: flutter
  app_image: ^x.y.z  # 假设的版本号

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

接下来,在你的Flutter应用中,你可以这样使用app_image插件来加载和处理图片:

import 'package:flutter/material.dart';
import 'package:app_image/app_image.dart';  // 假设的导入路径

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter App Image Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String? imageUrl = "https://example.com/path/to/your/image.jpg";  // 替换为你的图片URL

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('App Image Example'),
      ),
      body: Center(
        child: AppImage(
          imageUrl: imageUrl,
          placeholder: AssetImage('assets/placeholder.png'),  // 占位图,确保在assets文件夹中有此图片
          errorWidget: Icon(Icons.error),  // 加载错误时显示的widget
          onLoaded: (ImageProvider image) {
            // 图片加载成功后的回调
            print('Image loaded successfully');
          },
          onLoadError: (Object error, StackTrace? stackTrace) {
            // 图片加载错误时的回调
            print('Error loading image: $error');
          },
          // 其他可能的配置参数...
        ),
      ),
    );
  }
}

// 假设的AppImage组件实现(实际上你需要根据真实插件的API来实现)
class AppImage extends StatefulWidget {
  final String? imageUrl;
  final ImageProvider placeholder;
  final Widget errorWidget;
  final VoidCallback? onLoaded;
  final Function(Object, StackTrace?)? onLoadError;

  const AppImage({
    Key? key,
    this.imageUrl,
    required this.placeholder,
    required this.errorWidget,
    this.onLoaded,
    this.onLoadError,
  }) : super(key: key);

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

class _AppImageState extends State<AppImage> {
  ImageProvider? _imageProvider;

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

  void _loadImage() async {
    try {
      // 这里应该是加载图片的逻辑,但因为我们假设app_image插件的具体实现未知,
      // 所以这里简单地使用NetworkImage作为示例。
      if (widget.imageUrl != null) {
        _imageProvider = NetworkImage(widget.imageUrl!);
        precacheImage(_imageProvider!, context);
        widget.onLoaded?.call(_imageProvider!);
      }
    } catch (e, stackTrace) {
      widget.onLoadError?.call(e, stackTrace);
      _imageProvider = widget.placeholder;
    }

    if (mounted) {
      setState(() {});
    }
  }

  @override
  Widget build(BuildContext context) {
    return _imageProvider != null
        ? Image(
            image: _imageProvider!,
            errorWidget: widget.errorWidget,
          )
        : Container();  // 在图片加载前显示空容器(或你可以显示加载指示器)
  }
}

注意:上面的AppImage组件是一个假设的实现,用于展示如何处理图片加载的逻辑。在实际应用中,你应该根据app_image插件(或你选择的任何图片处理插件)的文档来实现相应的功能。

如果你实际上是在寻找一个具体的、流行的图片处理插件的使用示例,请告诉我,我可以为你提供如cached_network_imageimage_picker等插件的使用代码。

回到顶部