在 Flutter 中构建图像选择器【Flutter 专题 9】

简介: 什么是 Flutter 中的image_picker?在 Flutter 中从头开始编写图片选择器小部件会很乏味。Flutter 带有一个图片选择器插件,用于从设备图库中选择图片或从相机拍摄新照片。

什么是 Flutter 中的image_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方法打开选择对话框并显示手机的图库,从中选择图片。该sourceARG 指出该图片是从相册选择。


此处,source设置为ImageSource.gallery,因此图片是从用户的图库中选择的。


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



在上面的示例中,图片取自设备相机。此方法打开相机并选取用户拍摄的图片。该source: ImageSource.cameraarg 是什么打开设备上的照相机。

pickVideo

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



此方法会打开一个选择对话框以从手机图库中选择视频。pickVideo 当您希望从图库或手机的摄像机中选取视频时,可以使用 argsource: ImageSource.gallery 方法。从手机的图库中选择视频。


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



此方法允许用户从相机中选取视频。argsource: ImageSource.camera打开手机的摄像机,以便用户可以录制视频。然后将录制的视频用作选取的视频。

pickMultiImage

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



pickMultiImage使用户可以选择多个图片。argsource: ImageSource.gallery允许我们从手机图库中选择图片。


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


构建 Flutter 图片选择器应用程序

现在我们已经回顾了image_picker插件中的方法,让我们构建一个示例 Flutter 图片选择器应用程序,看看它们在实践中是如何工作的。


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


  • Flutter SDK:我们将使用它来编译、创建和运行我们的 Flutter 项目。它有一个 CLI 工具,flutter使我们能够从终端执行这些操作
  • VS Code:这是可选的,但非常适合编写 Flutter 项目。VS Code 有很棒的插件来增强你的 Flutter 编码体验
  • Android Studio:这个二进制文件是一个用于构建和编译原生 Android 项目的 IDE。我们还可以使用 Android Studio 创建、编译和运行 Flutter 项目。但大多数情况下,我们需要 Android Studio 来运行模拟器并从 VS Code 编译我们的 Flutter 项目

搭建 Flutter 项目的脚手架

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


首先,让我们搭建一个 Flutter 项目:


flutter create imagepickerprj

复制代码


这将在名为imagepickerprj. 一系列命令将级联我们的终端。在终端的末尾,您将看到运行新生成项目的说明:


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,它会在image_picker您保存pubspec.yaml文件后自动拉入。如果您不使用 VS Code,请运行以下命令以获取最新添加的依赖项:


flutter pub get

复制代码

创建小部件

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


Flutter 已经为我们设置了一些代码,但除了MyApp小部件之外我们不需要它。让我们从那里开始:


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 Camera。该Pick 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 示例"),
        ),
        body: Center(
          child: Column(
            children: [
              MaterialButton(
                color: Colors.blue,
                child: Text(
                  "Pick Image from 相册",
                  style: TextStyle(
                      color: Colors.white70, fontWeight: FontWeight.bold),
                ),
                onPressed: () {
                  _handleURLButtonPress(context, ImageSourceType.gallery);
                },
              ),
              MaterialButton(
                color: Colors.blue,
                child: Text(
                  "Pick Image from 相机",
                  style: TextStyle(
                      color: Colors.white70, fontWeight: FontWeight.bold),
                ),
                onPressed: () {
                  _handleURLButtonPress(context, ImageSourceType.camera);
                },
              ),
            ],
          ),
        ));
  }
}



我们有一个枚举,ImageSourceType,用于保存图片源类型、gallery,和相机。在HomePage小部件中,我们有一个方法,_handleURLButtonPress。此方法使用 arg type,它带有 的任何值ImageSourceType。它会打开ImageFromGalleryEx小部件,将图片源类型传递给小部件类。


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


Pick Image from Gallery按钮将 传递ImageSourceType.galleryImageFromGalleryEx小部件,告诉它我们将从图库中选择一个图片。该Pick Image from Camera按钮将 传递ImageSourceType.cameraImageFromGalleryEx小部件,告诉它打开手机的相机并将拍摄的照片作为所选图片。


现在,让我们对ImageFromGalleryEx小部件进行编码。

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() {
    // ignore: todo
    // TODO: implement initState
    super.initState();
    imagePicker = new ImagePicker();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text(type == ImageSourceType.camera
              ? "Image from 相机"
              : "Image from 相册")),
      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小部件内部,我们有以下变量:


  • _image 保存选择的图片,无论是从相册还是从相机
  • imagePicker持有ImagePicker类的实例
  • type保存小部件要使用的图片源的类型。它从小HomePage部件传递给小部件


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


build方法内部是Container小部件,它是小部件的子Center部件。我们Image.file根据_image变量的条件渲染。如果_image不是 null 或 undefined,那么我们知道它有一个图片,然后我们Image.file通过将_image变量传递给它来渲染小部件。


Image.file是一个小部件,用于从设备的本地存储渲染图片。如果_image变量中没有任何内容,我们将渲染Container小部件。这将Container显示一个相机图标。


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


现在,pickImage返回一个XFile实例。我们引用返回image.pathXFile实例image并将其传递给以File从中创建File实例。这个XFile实例是我们_image通过以下方式设置的状态:


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



这将导致ImageFromGalleryExState重新渲染并且Image.file将在_image变量中显示图片。


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

测试我们的 Flutter 图片选择器应用

打开您的 Android 模拟器,并从您的终端运行以下命令:


flutter run

复制代码


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


如果您使用的是 VS Code,则可以运行上述命令,或者只需lib/main.dart在编辑器中右键单击 ,然后单击run Without DebuggingStart Debugging


该应用程序将在您的 Android 模拟器中打开。

1.gif


结论

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


最后,我们构建了一个 Flutter 项目来演示如何image_picker在实际场景中使用该插件。


GitHub 上查找此项目的源代码。


相关文章
|
4月前
|
存储 开发框架 JavaScript
深入探讨Flutter中动态UI构建的原理、方法以及数据驱动视图的实现技巧
【6月更文挑战第11天】Flutter是高效的跨平台移动开发框架,以其热重载、高性能渲染和丰富组件库著称。本文探讨了Flutter中动态UI构建原理与数据驱动视图的实现。动态UI基于Widget树模型,状态变化触发UI更新。状态管理是关键,Flutter提供StatefulWidget、Provider、Redux等方式。使用ListView等可滚动组件和StreamBuilder等流式组件实现数据驱动视图的自动更新。响应式布局确保UI在不同设备上的适应性。Flutter为开发者构建动态、用户友好的界面提供了强大支持。
89 2
|
2月前
|
移动开发 Dart Android开发
构建未来:基于Flutter的跨平台移动应用开发
【7月更文挑战第52天】随着移动设备市场的多样化,跨平台移动应用的需求日益增长。传统的Android和iOS原生开发方式虽强大但成本较高,而新兴的跨平台框架如React Native、Xamarin等虽然提供了解决方案,但仍存在性能与体验上的妥协。本文将探讨使用Google推出的UI工具包Flutter进行高效、高性能的跨平台移动应用开发。我们将分析Flutter的核心架构,展示如何利用其丰富的组件库和高效的渲染引擎在Android和iOS之间实现无缝衔接,并讨论其在现代移动开发中的应用前景。
|
3月前
|
存储 安全 数据安全/隐私保护
构建安全Flutter应用 - 6个实用技巧
随着越来越多的敏感用户数据在Flutter应用中流通,应用安全已成为首要关注点。本文为您总结6大关键Flutter应用安全最佳实践,帮助开发者筑牢应用安全防线,保护用户隐私。
114 1
构建安全Flutter应用 - 6个实用技巧
|
2月前
|
开发者 监控 开发工具
如何将JSF应用送上云端?揭秘在Google Cloud Platform上部署JSF应用的神秘步骤
【8月更文挑战第31天】本文详细介绍如何在Google Cloud Platform (GCP) 上部署JavaServer Faces (JSF) 应用。首先,确保已准备好JSF应用并通过Maven构建WAR包。接着,使用Google Cloud SDK登录并配置GCP环境。然后,创建`app.yaml`文件以配置Google App Engine,并使用`gcloud app deploy`命令完成部署。最后,通过`gcloud app browse`访问应用,并利用GCP的监控和日志服务进行管理和故障排查。整个过程简单高效,帮助开发者轻松部署和管理JSF应用。
54 0
|
4月前
|
监控 Serverless 持续交付
阿里云云效产品使用问题之如何让流水线支持构建 flutter web 应用到 OSS
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
4月前
|
开发框架 移动开发 Android开发
构建高效移动应用:探索Flutter开发框架
【6月更文挑战第28天】随着移动设备的普及,用户对移动应用的需求日益增长。开发者面临着在众多平台间提供无缝体验的挑战。本文深入探讨了Flutter框架如何通过其跨平台特性、热重载功能以及丰富的组件库简化移动应用的开发流程,同时确保高性能和优雅的用户界面设计。
64 2
|
4月前
|
开发框架 Dart JavaScript
深入探讨Flutter中的Web支持功能,以及如何利用Flutter构建跨平台Web应用的最佳实践
【6月更文挑战第11天】Flutter,Google的开源跨平台框架,已延伸至Web支持,让开发者能用同一代码库构建移动和Web应用。Flutter Web基于Dart转JavaScript,利用WebAssembly和JavaScript在Web上运行。构建Web应用最佳实践包括选择合适项目、优化性能、进行兼容性测试和利用Flutter的声明式UI、热重载等优势。尽管性能挑战存在,Flutter Web为跨平台开发提供了更多机会和潜力。
89 1
|
5月前
|
Dart 安全 Android开发
构建未来:基于Flutter的跨平台移动应用开发
【5月更文挑战第28天】 在当今多元化的移动应用市场中,开发人员面临着为不同操作系统创建单独应用程序的挑战。这不仅增加了开发成本,也延长了上市时间。本文将探讨使用Google推出的开源UI工具包——Flutter进行高效、一致且高性能的跨平台移动应用开发。我们将深入分析Flutter框架的核心特性,并通过一个实际案例来阐述如何利用Dart语言和热重载功能快速迭代原型设计。文章的目标是向读者展示Flutter不仅能够缩减开发周期,还能提供接近原生应用的用户体验。
|
5月前
|
开发框架 Dart 前端开发
【Flutter前端技术开发专栏】Flutter中的Web支持:构建跨平台Web应用
【4月更文挑战第30天】Flutter,Google的开源跨平台框架,已延伸至Web领域,让开发者能用同一代码库构建移动和Web应用。Flutter Web通过将Dart代码编译成JavaScript和WASM运行在Web上。尽管性能可能不及原生Web应用,但适合交互性强、UI复杂的应用。开发者应关注性能优化、兼容性测试,并利用Flutter的声明式UI、热重载等优势。随着其发展,Flutter Web为跨平台开发带来更多潜力。
128 0
【Flutter前端技术开发专栏】Flutter中的Web支持:构建跨平台Web应用
|
5月前
|
Dart IDE Android开发
构建未来:基于Flutter的跨平台移动应用开发探索
【5月更文挑战第18天】在移动应用开发的世界中,跨平台技术正迅速成为一股不可忽视的力量。特别是Google推出的Flutter框架以其高效的性能和一套代码适应多平台的特性受到开发者的青睐。本文旨在探讨Flutter框架的核心优势、开发流程以及其在安卓与iOS平台上的应用实践,为开发者提供一个全面的技术分析视角,并展望Flutter在未来移动开发领域中的潜在发展。