在Flutter中创建图像采集器-Flutter组件实用教程

1,790 阅读9分钟

图像采集器是任何应用程序中最广泛使用的组件之一。许多流行的应用程序,如Facebook、Twitter、Instagram、WhatsApp等,都有一个图像采集器,使用户能够从他们的设备中选择文件作为个人资料图片或与他们的朋友分享。

在移动应用程序中,图像选取器最常见的用例是为用户的个人资料设置一个头像。在本教程中,我们将向您展示如何在Flutter中创建一个图像采集器。我们将建立一个Flutter应用实例,使用户能够从图库中选择照片或从设备的相机中拍摄照片。

以下是我们要介绍的内容。

什么是 Flutterimage_picker

在 Flutter 中从头开始编码一个图像拾取器部件将是非常乏味的。Flutter自带了一个图像采集器插件,用于从设备库中采集图像或从相机中拍摄新的照片。

image_picker 插件从它输出的ImagePicker 类中暴露了一些有用的方法。

import 'package:image_picker/image_picker.dart';

ImagePicker picker = ImagePicker();

picker 实例有公共方法,我们将调用这些方法来打开图像选择对话框。让我们来看看这些方法。

pickImage

XFile? image = await picker.pickImage(source: ImageSource.gallery);

pickImage 方法打开选择对话框并显示手机的图片库,从中选择图片。source 参数说明了要从哪里选择图片。

在这里,source 被设置为ImageSource.gallery ,所以图像是从用户的图片库中选择的。

XFile? image = await picker.pickImage(source: ImageSource.camera);

在上面的例子中,图像是从设备的摄像头中提取的。这个方法打开相机并选择用户拍下的图片。source: ImageSource.camera 参数是打开设备相机的原因。

pickVideo

XFile? image = await picker.pickVideo(source: ImageSource.gallery);

这个方法打开一个选择对话框,从手机的图片库中挑选一个视频。当你想从图片库或手机的摄像头中挑选视频时,你会使用pickVideo 方法。argsource: ImageSource.gallery 导致视频从手机的图库中被选中。

XFile? photo = await picker.pickVideo(source: ImageSource.camera);

这个方法允许用户从相机中挑选视频。参数source: ImageSource.camera 打开手机的摄像头,以便用户可以录制视频。录制的视频然后被用作挑选的视频。

pickMultiImage

List<XFile>? images = await picker.pickMultiImage(source: ImageSource.gallery);

pickMultiImage 使用户可以挑选多个图像。source: ImageSource.gallery 这个参数允许我们从手机的图片库中挑选图片。

List<XFile>? photos = await picker.pickMultiImage(source: ImageSource.camera);

构建一个Flutter图像采集器应用程序

现在我们已经回顾了image_picker 插件中的方法,让我们建立一个Flutter图像采集器应用的例子,看看它们在实践中如何工作。

在我们开始之前,请确保你的机器上已经安装了以下工具和二进制文件。

  • Flutter SDK。我们将使用它来编译、创建和运行我们的Flutter项目。它有一个CLI工具,flutter ,它使我们能够从终端完成这些事情
  • VS代码。这是可选的,但对Flutter项目的编码很有帮助。VS Code有很好的插件来提高您对Flutter的编码体验。
  • Android Studio。这个二进制文件是一个用于构建和编译原生 Android 项目的 IDE。我们也可以使用 Android Studio 创建、编译和运行 Flutter 项目。但大多数情况下,我们需要 Android Studio 来运行仿真器,并从 VS Code 中编译我们的 Flutter 项目。

构建Flutter项目的脚手架

现在我们已经完成了必要的工具和二进制文件的安装,是时候建立我们的Flutter图像选取器示例应用程序了。

首先,让我们搭建一个Flutter项目的脚手架。

flutter create imagepickerprj

这将在一个名为imagepickerprj 的文件夹中创建一个Flutter项目。一系列的命令将在我们的终端上层层递减。在终端的最后,你会看到运行新生成的项目的说明。

In order to run your application, type:

  $ cd imagepickerprj
  $ flutter run

To enable null safety, type:

  $ cd imagepickerprj
  $ dart migrate --apply-changes

Your application code is in imagepickerprj/lib/main.dart.

我们现在不会运行它,但让我们把它移到文件夹里面。

cd imagepickerprj

添加image_picker 插件

下一步是将image_picker 插件添加到我们的 Flutter 项目中。

打开pubspec.yaml 文件,将image_picker 加入到dependencies 部分。

dependencies:
  flutter:
    sdk: flutter
  image_picker: ^0.8.2

如果你使用的是VS Code,一旦你保存了pubspec.yaml 文件,它就会自动拉入image_picker 。如果您没有使用VS Code,请运行以下命令以拉入最新添加的依赖关系。

flutter pub get

创建部件

在我们的imagepickerprj 项目中,我们的主文件位于lib/ 文件夹中。这是main.dart 文件,它是任何Flutter项目/应用程序的入口。所以这就是我们要开始添加大部分代码的地方。

Flutter已经为我们设置了一些代码,但除了在MyApp widget中,我们不会需要它。让我们从那里开始。

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

我们的Flutter图片选取器应用将有两个屏幕。

  • HomePage 将列出两个按钮:Pick Image from Gallery ,和Pick Image from CameraPick Image from Gallery 将打开一个ImageFromGalleryEx 屏幕,在那里我们可以从我们的图库中挑选图片,而Pick Image from Camera 将打开一个ImageFromGalleryEx 屏幕,在那里我们可以从我们的相机中拍摄图片并使用该图片作为挑选的图片
  • ImageFromGalleryEx 将处理从图库和相机中挑选图像的问题。它将知道根据发送给它的源类型来处理什么。它还将显示所选图片

现在让我们给它们编码。

HomePage

enum ImageSourceType { gallery, camera }

class HomePage extends StatelessWidget {
  void _handleURLButtonPress(BuildContext context, var type) {
    Navigator.push(context,
        MaterialPageRoute(builder: (context) => ImageFromGalleryEx(type)));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Image Picker Example"),
        ),
        body: Center(
          child: Column(
            children: [
              MaterialButton(
                color: Colors.blue,
                child: Text(
                  "Pick Image from Gallery",
                  style: TextStyle(
                      color: Colors.white70, fontWeight: FontWeight.bold),
                ),
                onPressed: () {
                  _handleURLButtonPress(context, ImageSourceType.gallery);
                },
              ),
              MaterialButton(
                color: Colors.blue,
                child: Text(
                  "Pick Image from Camera",
                  style: TextStyle(
                      color: Colors.white70, fontWeight: FontWeight.bold),
                ),
                onPressed: () {
                  _handleURLButtonPress(context, ImageSourceType.camera);
                },
              ),
            ],
          ),
        ));
  }
}

我们有一个枚举,ImageSourceType ,持有图像源类型,画廊和相机。
HomePage widget中,我们有一个方法,_handleURLButtonPress 。这个方法使用参数type ,它包含了ImageSourceType 的任何值。它打开ImageFromGalleryEx widget,把图像源类型传给widget类。

build 方法中,我们看到它渲染了两个按钮,正如我们前面所说:Pick Image from Gallery ,和Pick Image from Camera 。每个按钮上都设置了一个onPressed 事件。当按钮被按下时,这些事件会调用_handleURLButtonPress 方法。

Pick Image from Gallery 按钮将ImageSourceType.gallery 传递给ImageFromGalleryEx 小部件,告诉它我们将从画廊中挑选一张图片。Pick Image from Camera 按钮将ImageSourceType.camera 传递给ImageFromGalleryEx 小组件,告诉它打开手机的摄像头,并将拍摄的图片作为所选图片。

现在,让我们给ImageFromGalleryEx widget编码。

ImageFromGalleryEx

class ImageFromGalleryEx extends StatefulWidget {
  final type;
  ImageFromGalleryEx(this.type);

  @override
  ImageFromGalleryExState createState() => ImageFromGalleryExState(this.type);
}

class ImageFromGalleryExState extends State<ImageFromGalleryEx> {
  var _image;
  var imagePicker;
  var type;

  ImageFromGalleryExState(this.type);

  @override
  void initState() {
    super.initState();
    imagePicker = new ImagePicker();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text(type == ImageSourceType.camera
              ? "Image from Camera"
              : "Image from Gallery")),
      body: Column(
        children: <Widget>[
          SizedBox(
            height: 52,
          ),
          Center(
            child: GestureDetector(
              onTap: () async {
                var source = type == ImageSourceType.camera
                    ? ImageSource.camera
                    : ImageSource.gallery;
                XFile image = await imagePicker.pickImage(
                    source: source, imageQuality: 50, preferredCameraDevice: CameraDevice.front);
                setState(() {
                  _image = File(image.path);
                });
              },
              child: Container(
                width: 200,
                height: 200,
                decoration: BoxDecoration(
                    color: Colors.red[200]),
                child: _image != null
                    ? Image.file(
                          _image,
                          width: 200.0,
                          height: 200.0,
                          fit: BoxFit.fitHeight,
                        )
                    : Container(
                        decoration: BoxDecoration(
                            color: Colors.red[200]),
                        width: 200,
                        height: 200,
                        child: Icon(
                          Icons.camera_alt,
                          color: Colors.grey[800],
                        ),
                      ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

在这里,我们有ImageFromGalleryEx ,一个有状态的部件,和ImageFromGalleryExState ,它持有ImageFromGalleryEx 部件的状态。

ImageFromGalleryExState widget里面,我们有以下的变量。

  • _image 保存所选的图像,无论是从画廊还是从相机中提取的图像。
  • imagePicker 保持ImagePicker 类的实例
  • type 保存小组件要使用的图像源的类型。它从HomePage 小组件传递给小组件。

我们也有一个initState 方法,它首先被插入到小组件树中。我们用这个方法来初始化和创建ImagePicker 类的实例,然后把它分配给imagePicker 变量。

build 方法里面是Container widget,它是Center widget的一个子程序。我们根据_image 变量的条件来渲染Image.file 。如果_image 不是空的或未定义的,那么我们知道它有一个图像,然后我们通过传递_image 变量给它来渲染Image.file widget。

这个Image.file 是一个小部件,用来渲染设备本地存储的图像。
如果_image 变量中没有任何东西,我们就渲染Container 小部件。这个Container 显示一个相机图标。

GestureDetector 是所有这些小部件的父级。它有一个onTap 事件注册到它。当这个GestureDetector 里面的小部件被点击的时候,这个事件就会被触发。onTap 处理程序从imagePicker 实例中调用pickImage 方法。它从type 变量中推断出图像的来源,并将其传递给pickImage 方法。然后,它传递图像的质量(imageQuality: 50 ),最后是首选的相机设备preferredCameraDevice: CameraDevice.front 。这使得它选择我们手机的前置摄像头。

现在,pickImage 返回一个XFile 实例。我们从XFile 实例中引用image 返回的image.path ,并将其传递给File ,从中创建一个File 实例。这个XFile 实例就是我们通过它设置为_image 状态。

setState(() {
    _image = File(image.path);
});

这将导致ImageFromGalleryExState 重新渲染,Image.file 将显示_image 变量中的图像。

现在我们完成了代码,让我们测试运行我们的应用程序。

测试我们的Flutter图像采集器应用程序

打开你的安卓模拟器,从你的终端,运行以下命令。

flutter run

这将编译和构建项目,然后在您的安卓模拟器中运行该应用程序。

如果你使用的是VS代码,你可以运行上述命令,或者简单地在编辑器中右击lib/main.dart ,然后点击run Without DebuggingStart Debugging

该应用程序将在你的安卓模拟器中打开。

HomePage

Flutter Image Picker Example App Home Page

从图库中挑选图片

Flutter Image Picker From Gallery Example Flutter Image Picker From Gallery Example Flutter Image Picker From Gallery Example

从相机中选取图片

Flutter Image Picker From Camera Example Flutter Image Picker From Camera Example Flutter Image Picker From Camera Example

总结

在本教程中我们学到了很多东西。我们首先介绍了Flutter图像采集器组件的常见用例。然后,我们介绍了Flutter的插件image_picker 。我们学习了如何初始化image_picker 插件的ImagePicker 类,并回顾了ImagePicker 类中的方法。

最后,我们建立了一个Flutter项目来演示如何在真实世界的场景中使用image_picker 插件。

GitHub上找到这个项目的源代码。