image_picker 0.6.7+3

  • Readme
  • Changelog
  • Example
  • Installing
  • 100

Image Picker plugin for Flutter #

pub package

一个适用于iOS和Android的Flutter插件,用于从图像库中拾取图像并使用相机拍摄新照片.

Installation #

首先, 在您的pubspec.yaml文件中将image_picker添加为依赖项 .

iOS #

将以下密钥添加到您的Info.plist文件中,该文件位于<project root>/ios/Runner/Info.plist

  • NSPhotoLibraryUsageDescription描述为什么您的应用需要照片库的权限. 在视觉编辑器中,这称为" 隐私-照片库使用说明 ".
  • NSCameraUsageDescription描述为什么您的应用需要访问相机. 在视觉编辑器中,这称为" 隐私-相机使用说明 ".
  • NSMicrophoneUsageDescription描述如果您打算录制视频,为什么您的应用程序需要使用麦克风. 在可视编辑器中,这称为" 隐私-麦克风使用说明 ".

Android #

API 29+

无需配置-插件应该可以立即使用.

API < 29

android:requestLegacyExternalStorage="true"作为属性添加到AndroidManifest.xml中的<application>标签. 在定位到Android Q的应用上,默认情况下该属性false .

Example #

import 'package:image_picker/image_picker.dart';

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

class _MyHomePageState extends State<MyHomePage> {
  File _image;
  final picker = ImagePicker();

  Future getImage() async {
    final pickedFile = await picker.getImage(source: ImageSource.camera);

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Image Picker Example'),
      ),
      body: Center(
        child: _image == null
            ? Text('No image selected.')
            : Image.file(_image),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: getImage,
        tooltip: 'Pick Image',
        child: Icon(Icons.add_a_photo),
      ),
    );
  }
}

Handling MainActivity destruction on Android #

Android系统-尽管很少-有时会在image_picker完成后杀死MainActivity. 发生这种情况时,我们丢失了从image_picker中选择的数据. 在这种情况下,可以使用retrieveLostData来检索丢失的数据. 例如:

Future<void> retrieveLostData() async {
  final LostData response =
      await picker.getLostData();
  if (response == null) {
    return;
  }
  if (response.file != null) {
    setState(() {
      if (response.type == RetrieveType.video) {
        _handleVideo(response.file);
      } else {
        _handleImage(response.file);
      }
    });
  } else {
    _handleError(response.exception);
  }
}

无法检测到何时发生,因此在正确的位置调用此方法至关重要. 我们建议将其连接到某种启动检查中. 请参考示例应用程序以了解我们如何使用它.

Deprecation warnings in pickImage, pickVideo and LostDataResponse #

从image_picker插件的0.6.7版本开始 ,该插件的API进行了少许更改,以允许存在Web实施.

返回dart:io File对象旧方法被标记为已弃用 ,并引入了一组新的返回PickedFile对象的方法.

How to migrate from to ^0.6.7 #

Instantiate the ImagePicker

新的ImagePicker API不再依赖静态方法,因此您需要做的第一件事是在需要的地方创建插件的新实例:

final _picker = ImagePicker();

Call the new methods

新方法接收与以前相同的参数 ,但是它们返回PickedFile而不是File . 该LostDataResponse类已被替换为LostData .

旧API新API
File image = await ImagePicker.pickImage(...)PickedFile image = await _picker.getImage(...)
File video = await ImagePicker.pickVideo(...)PickedFile video = await _picker.getVideo(...)
LostDataResponse response = await ImagePicker.retrieveLostData()LostData response = await _picker.getLostData()

PickedFile to File

如果您的应用需要dart:io File对象才能运行,则可以将PickedFile转换为File如下所示:

final pickedFile = await _picker.getImage(...);
final File file = File(pickedFile.path);

如果需要,您也可以直接从pickedFile中检索字节:

final bytes = await pickedFile.readAsBytes();

Getting ready for the web platform

请注意,在Web平台( kIsWeb == true )上, File不可用,因此PickedFilepath将指向网络资源:

if (kIsWeb) {
  image = Image.network(pickedFile.path);
} else {
  image = Image.file(File(pickedFile.path));
}

或者,可以以牺牲内存利用率为代价来统一代码:

image = Image.memory(await pickedFile.readAsBytes())

查看对版本0.6.7中引入的example应用程序所做的更改,以了解在那里应用的迁移步骤.

0.6.7+3 #

  • 修复了示例应用程序:
    • 使网络中的视频开始静音. 这样可以跨浏览器自动播放.
    • 防止应用程序过早处置视频控制器.

0.6.7+2 #

  • iOS:如果窗口的根视图控制器已经在显示其他视图控制器,则修复无法显示的相册/图像选择器.

0.6.7+1 #

  • 将网络支持添加到示例应用程序.

0.6.7 #

  • 使用新的platform_interface软件包.
  • 此更改将旧方法标记为deprecated . 请查看自述文件以获取向新API迁移的说明.

0.6.6+5 #

  • 将平台接口的版本固定为1.0.0,直到可以进行插件重构为止.

0.6.6+4 #

  • 修复错误,有时双击取消按钮会崩溃.

0.6.6+3 #

  • 更新自述文件

0.6.6+2 #

  • 将dart依赖关系的下限更新为2.1.0.

0.6.6+1 #

  • Android:始终使用URI来获取图像/视频数据.

0.6.6 #

  • 使用新的platform_interface包.

0.6.5+3 #

  • 将核心插件移到子目录以允许联盟.

0.6.5+2 #

  • iOS:修复了多次敲击图库中的图像时崩溃的问题.

0.6.5+1 #

  • 修复CocoaPods podspec棉绒警告.

0.6.5 #

  • 设置视频录制的最大持续时间.
  • 修复一些现有的XCTests.

0.6.4 #

  • 添加新参数以选择首选的摄像头设备.

0.6.3+4 #

  • 使学究的dev_dependency明确.

0.6.3+3 #

  • Android:修复了externalFilesDirectory不存在时的崩溃.

0.6.3+2 #

  • 将RoboElectric依赖项提高到4.3.1,并更新资源使用情况.

0.6.3+1 #

  • 修复了Android V2嵌入迁移后示例应用程序不会启动图像选择器的问题.

0.6.3 #

  • 支持Android V2嵌入.
  • 迁移到使用新的e2e测试绑定.

0.6.2+3 #

  • 从pubspec.yaml中删除不推荐使用的author:字段
  • 将插件迁移到pubspec平台清单.
  • 需要Flutter SDK 1.10.0或更高版本.

0.6.2+2 #

  • Android:不必缩放图像时,还原图像文件返回逻辑. 修复由0.6.2 + 1引起的旋转回归
  • 应用示例:添加一个对话框以在选择图像时输入maxWidthmaxHeightquality .

0.6.2+1 #

  • Android:修复了当选择非图像文件时的崩溃问题.
  • Android:修复不需要的位图缩放.

0.6.2 #

  • iOS:修复了从库中选取内容会导致iOS 13崩溃的问题.

0.6.1+11 #

  • 稳定性和可维护性:更新文档,添加单元测试.

0.6.1+10 #

  • iOS:修复缩放图像时的图像方向问题.

0.6.1+9 #

  • 删除AndroidX警告.

0.6.1+8 #

  • 修复iOS构建和分析器警告.

0.6.1+7 #

  • Android:修复ImagePickerPlugin#onCreate投放上下文会导致异常.

0.6.1+6 #

  • 定义iOS的clang模块

0.6.1+5 #

  • 更新和迁移iOS示例项目.

0.6.1+4 #

  • Android:修复一个回归,该回归使得retrieveLostImage不再起作用.
  • 设置Android单元测试以测试ImagePickerCache并添加图像质量缓存测试.

0.6.1+3 #

  • 修正iOS:修正缩放后所选取图片的方向.
  • 删除试图规范方向的不必要代码.
  • 简单的XCTest代码修复.

0.6.1+2 #

  • androidx.core:core:1.0.2替换对androidx.legacy:legacy-support-v4:1.0.0依赖关系

0.6.1+1 #

  • 添加对androidx.annotation:annotation:1.0.0依赖关系.

0.6.1 #

  • 新功能:获取具有自定义质量的图像. 在拾取图像时,用户可以传递imageQuality参数来压缩图像.

0.6.0+20 #

  • Android:迁移了信息缓存方法以使用实例方法.

0.6.0+19 #

  • Android: Fix memory leak due not unregistering ActivityLifecycleCallbacks.

0.6.0+18 #

  • 修复示例中的视频播放并更新video_player插件依赖性.

0.6.0+17 #

  • iOS:修复了用户使用iOS 11下的设备从相机捕获图像时崩溃的问题.

0.6.0+16 #

  • iOS模拟器:尝试从不存在的相机拍摄图像后修复挂起问题.

0.6.0+15 #

  • Android:拒绝权限而不是忽略权限时会引发异常.

0.6.0+14 #

  • 修复自述文件中的错字.

0.6.0+13 #

  • Android的修正:修正了在某些情况下,当用户从图库中拾取图像时发生崩溃的问题.

0.6.0+12 #

  • 在iOS实现中,将类而不是struct用于GIFInfo .

0.6.0+11 #

  • 不要使用模块导入.

0.6.0+10 #

  • iOS:支持从图库中选择GIF.

0.6.0+9 #

  • 将缺少的模板类型参数添加到invokeMethod调用中.
  • 将Flutter的最低版本提高到1.5.0.
  • 必要时,将invokeMethod替换为invokeMapMethod.

0.6.0+8 #

  • 错误修正:将遗漏的返回语句添加到image_picker示例中.

0.6.0+7 #

  • iOS:重命名对象以遵循Objective-C命名约定,以避免与其他iOS库/框架冲突.

0.6.0+6 #

  • iOS:现在,拾取的图像具有原始图像中的所有正确元数据,包括GPS,方向等.

0.6.0+5 #

  • iOS:添加缺少的导入.

0.6.0+4 #

  • iOS:使用第一个字节确定原始图像类型.
  • iOS:添加了XCTest目标.
  • iOS:现在,拾取的图像具有从原始图像复制的正确EXIF数据.

0.6.0+3 #

  • Android:修复了由于在错误的线程上发送回复消息而导致的断言失败.

0.6.0+2 #

  • Android:图像以其真实扩展名保存,而不是始终使用.jpg .

0.6.0+1 #

  • Android:从远程URL选取图像时使用正确的后缀语法.

0.6.0 #

  • iOS的重大突破:现在,在拾取视频时返回的File对象始终具有正确的路径. 在进行此更改之前,返回的路径可能在其前面添加了file:// .

0.5.4+3 #

  • 修复示例应用无法加载所选视频的问题.

0.5.4+2 #

  • 如果Android> = M上的清单中存在相机,则请求相机权限.

0.5.4+1 #

  • Bugfix iOS:如果先访问相机,则取消按钮在图库中不可见.

0.5.4 #

  • 在MainActivity被杀死之后,添加retrieveLostData以检索丢失的数据.

0.5.3+2 #

  • Android:修复了选择图像/视频后MainActivity被破坏时的崩溃问题.

0.5.3+1 #

  • 将最低部署iOS版本更新为8.0.

0.5.3 #

  • 修复了从Android上的Google相册返回的错误路径.

0.5.2 #

  • 如果访问被拒绝,请检查iOS摄像机的授权状态并返回错误.

0.5.1 #

  • Android:如果图像来自图库,请不要在缩放后删除原始图像.

0.5.0+9 #

  • 删除不必要的临时视频文件路径.

0.5.0+8 #

  • 修复了图片Uri的GooglePhotos授权错误.

0.5.0+7 #

  • 修复了从yandex.disk和Dropbox中选择图像时的崩溃问题.

0.5.0+6 #

  • 如果原始图像已缩放,请删除它.

0.5.0+5 #

  • 删除不必要的相机许可.

0.5.0+4 #

  • 保存图像时保持透明.

0.5.0+3 #

  • 修复了在没有活动的情况下注册Image Picker时Android崩溃的问题.

0.5.0+2 #

  • 在构建时记录有关先前AndroidX迁移的更详细的警告.

0.5.0+1 #

  • 修复了用户在Android上快速连续调用插件时崩溃的问题.

0.5.0 #

  • 突破性的改变 . 从已弃用的原始Android支持库迁移到AndroidX. 这不应该导致任何功能上的变化,但是如果使用原始插件的Android应用程序也必须进行迁移 ,因此这些应用程序也必须进行迁移 .

0.4.12+1 #

  • 修复了在某些设备上从图像选择器选择下载的图像时崩溃的问题.

0.4.12 #

  • 修复了用户多次敲击图像时崩溃的问题.

0.4.11 #

  • 使用api定义support-v4依赖关系以允许自动版本解析.

0.4.10 #

  • 依赖完整的support-v4库以易于使用(修复了与Firebase和库的冲突)

0.4.9 #

  • 错误修正:在iOS上,无法在调整大小的图像上出现一像素的白线.

0.4.8 #

  • 将完整的com.android.support:appcompat-v7依赖项替换为com.android.support:support-core-utils ,从而使APK尺寸更小.
  • 将支持库升级到27.1.1

0.4.7 #

  • 添加了缺少的video_player程序包dev依赖性.

0.4.6 #

  • 添加了对选择远程图像的支持.

0.4.5 #

  • 错误修正,代码清除,更多测试范围.

0.4.4 #

  • 更新了Gradle工具以匹配Android Studio 3.1.2.

0.4.3 #

  • 错误修正:在iOS上,当用户取消选择视频时, pickVideo方法现在将返回null.

0.4.2 #

  • 添加了对选择视频的支持.
  • 更新了示例应用程序以显示视频预览.

0.4.1 #

  • 错误修正:当用户取消选择图像时, pickImage方法现在将返回null,而不是无限期地挂起.
  • 删除了使用相机拍照的第三方库依赖.

0.4.0 #

  • 突破性的改变 . 现在需要pickImagesource参数. 另外, ImageSource.any选项不再存在.
  • 使用本地Android图像库来选择图像,而不是自定义UI.

0.3.1 #

  • 错误修正:使用ImageSource.camera时,Android版本正确要求运行时相机权限.

0.3.0 #

  • 突破性的改变 . 设置SDK约束以匹配Flutter beta版本.

0.2.1 #

  • 将Android项目模板简化并升级到Android SDK 27.
  • 更新了软件包说明.

0.2.0 #

  • 突破性的改变 . 升级到Gradle 4.1和Android Studio Gradle插件3.0.1. 较早的Flutter项目也需要升级其Gradle设置才能使用此版本的插件. 说明可以在这里找到.

0.1.5 #

  • 为iOS类型添加了FLT前缀

0.1.4 #

  • 错误修正:取消图像拾取引发异常.
  • 错误修正:插件状态管理中的错误.

0.1.3 #

  • 在pickImage中添加了可选的source参数,用于控制图像的来源.

0.1.2 #

  • 向pickImage添加了可选的maxWidth和maxHeight参数.

0.1.1 #

  • 更新了Gradle存储库声明,以避免在使用该应用程序中进行手动配置.

0.1.0+1 #

  • 更新了pubspec.yaml中的自述文件和说明

0.1.0 #

  • 更新了依赖性
  • 重大更改 :您需要在android/build.gradle的存储库部分中添加一个带有" https://maven.google.com"端点的maven部分. 例如:
allprojects {
    repositories {
        jcenter()
        maven {                              // NEW
            url "https://maven.google.com"   // NEW
        }                                    // NEW
    }
}

0.0.3 #

  • 修复了显示"相机/图库"选择对话框时iPad崩溃的问题

0.0.2+2 #

  • 更新的自述文件

0.0.2+1 #

  • 更新的自述文件

0.0.2 #

  • 修复了尝试在没有摄像头的设备(例如模拟器)上访问摄像头时崩溃的问题

0.0.1 #

  • 初始发行

example/lib/main.dart

// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: public_member_api_docs

import 'dart:async';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/basic.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:image_picker/image_picker.dart';
import 'package:video_player/video_player.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Image Picker Demo',
      home: MyHomePage(title: 'Image Picker Example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  PickedFile _imageFile;
  dynamic _pickImageError;
  bool isVideo = false;
  VideoPlayerController _controller;
  VideoPlayerController _toBeDisposed;
  String _retrieveDataError;

  final ImagePicker _picker = ImagePicker();
  final TextEditingController maxWidthController = TextEditingController();
  final TextEditingController maxHeightController = TextEditingController();
  final TextEditingController qualityController = TextEditingController();

  Future<void> _playVideo(PickedFile file) async {
    if (file != null && mounted) {
      await _disposeVideoController();
      if (kIsWeb) {
        _controller = VideoPlayerController.network(file.path);
        // In web, most browsers won't honor a programmatic call to .play
        // if the video has a sound track (and is not muted).
        // Mute the video so it auto-plays in web!
        // This is not needed if the call to .play is the result of user
        // interaction (clicking on a "play" button, for example).
        await _controller.setVolume(0.0);
      } else {
        _controller = VideoPlayerController.file(File(file.path));
        await _controller.setVolume(1.0);
      }
      await _controller.initialize();
      await _controller.setLooping(true);
      await _controller.play();
      setState(() {});
    }
  }

  void _onImageButtonPressed(ImageSource source, {BuildContext context}) async {
    if (_controller != null) {
      await _controller.setVolume(0.0);
    }
    if (isVideo) {
      final PickedFile file = await _picker.getVideo(
          source: source, maxDuration: const Duration(seconds: 10));
      await _playVideo(file);
    } else {
      await _displayPickImageDialog(context,
          (double maxWidth, double maxHeight, int quality) async {
        try {
          final pickedFile = await _picker.getImage(
            source: source,
            maxWidth: maxWidth,
            maxHeight: maxHeight,
            imageQuality: quality,
          );
          setState(() {
            _imageFile = pickedFile;
          });
        } catch (e) {
          setState(() {
            _pickImageError = e;
          });
        }
      });
    }
  }

  @override
  void deactivate() {
    if (_controller != null) {
      _controller.setVolume(0.0);
      _controller.pause();
    }
    super.deactivate();
  }

  @override
  void dispose() {
    _disposeVideoController();
    maxWidthController.dispose();
    maxHeightController.dispose();
    qualityController.dispose();
    super.dispose();
  }

  Future<void> _disposeVideoController() async {
    if (_toBeDisposed != null) {
      await _toBeDisposed.dispose();
    }
    _toBeDisposed = _controller;
    _controller = null;
  }

  Widget _previewVideo() {
    final Text retrieveError = _getRetrieveErrorWidget();
    if (retrieveError != null) {
      return retrieveError;
    }
    if (_controller == null) {
      return const Text(
        'You have not yet picked a video',
        textAlign: TextAlign.center,
      );
    }
    return Padding(
      padding: const EdgeInsets.all(10.0),
      child: AspectRatioVideo(_controller),
    );
  }

  Widget _previewImage() {
    final Text retrieveError = _getRetrieveErrorWidget();
    if (retrieveError != null) {
      return retrieveError;
    }
    if (_imageFile != null) {
      if (kIsWeb) {
        // Why network?
        // See https://pub.dev/packages/image_picker#getting-ready-for-the-web-platform
        return Image.network(_imageFile.path);
      } else {
        return Image.file(File(_imageFile.path));
      }
    } else if (_pickImageError != null) {
      return Text(
        'Pick image error: $_pickImageError',
        textAlign: TextAlign.center,
      );
    } else {
      return const Text(
        'You have not yet picked an image.',
        textAlign: TextAlign.center,
      );
    }
  }

  Future<void> retrieveLostData() async {
    final LostData response = await _picker.getLostData();
    if (response.isEmpty) {
      return;
    }
    if (response.file != null) {
      if (response.type == RetrieveType.video) {
        isVideo = true;
        await _playVideo(response.file);
      } else {
        isVideo = false;
        setState(() {
          _imageFile = response.file;
        });
      }
    } else {
      _retrieveDataError = response.exception.code;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: !kIsWeb && defaultTargetPlatform == TargetPlatform.android
            ? FutureBuilder<void>(
                future: retrieveLostData(),
                builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
                  switch (snapshot.connectionState) {
                    case ConnectionState.none:
                    case ConnectionState.waiting:
                      return const Text(
                        'You have not yet picked an image.',
                        textAlign: TextAlign.center,
                      );
                    case ConnectionState.done:
                      return isVideo ? _previewVideo() : _previewImage();
                    default:
                      if (snapshot.hasError) {
                        return Text(
                          'Pick image/video error: ${snapshot.error}}',
                          textAlign: TextAlign.center,
                        );
                      } else {
                        return const Text(
                          'You have not yet picked an image.',
                          textAlign: TextAlign.center,
                        );
                      }
                  }
                },
              )
            : (isVideo ? _previewVideo() : _previewImage()),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          FloatingActionButton(
            onPressed: () {
              isVideo = false;
              _onImageButtonPressed(ImageSource.gallery, context: context);
            },
            heroTag: 'image0',
            tooltip: 'Pick Image from gallery',
            child: const Icon(Icons.photo_library),
          ),
          Padding(
            padding: const EdgeInsets.only(top: 16.0),
            child: FloatingActionButton(
              onPressed: () {
                isVideo = false;
                _onImageButtonPressed(ImageSource.camera, context: context);
              },
              heroTag: 'image1',
              tooltip: 'Take a Photo',
              child: const Icon(Icons.camera_alt),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(top: 16.0),
            child: FloatingActionButton(
              backgroundColor: Colors.red,
              onPressed: () {
                isVideo = true;
                _onImageButtonPressed(ImageSource.gallery);
              },
              heroTag: 'video0',
              tooltip: 'Pick Video from gallery',
              child: const Icon(Icons.video_library),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(top: 16.0),
            child: FloatingActionButton(
              backgroundColor: Colors.red,
              onPressed: () {
                isVideo = true;
                _onImageButtonPressed(ImageSource.camera);
              },
              heroTag: 'video1',
              tooltip: 'Take a Video',
              child: const Icon(Icons.videocam),
            ),
          ),
        ],
      ),
    );
  }

  Text _getRetrieveErrorWidget() {
    if (_retrieveDataError != null) {
      final Text result = Text(_retrieveDataError);
      _retrieveDataError = null;
      return result;
    }
    return null;
  }

  Future<void> _displayPickImageDialog(
      BuildContext context, OnPickImageCallback onPick) async {
    return showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: Text('Add optional parameters'),
            content: Column(
              children: <Widget>[
                TextField(
                  controller: maxWidthController,
                  keyboardType: TextInputType.numberWithOptions(decimal: true),
                  decoration:
                      InputDecoration(hintText: "Enter maxWidth if desired"),
                ),
                TextField(
                  controller: maxHeightController,
                  keyboardType: TextInputType.numberWithOptions(decimal: true),
                  decoration:
                      InputDecoration(hintText: "Enter maxHeight if desired"),
                ),
                TextField(
                  controller: qualityController,
                  keyboardType: TextInputType.number,
                  decoration:
                      InputDecoration(hintText: "Enter quality if desired"),
                ),
              ],
            ),
            actions: <Widget>[
              FlatButton(
                child: const Text('CANCEL'),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
              FlatButton(
                  child: const Text('PICK'),
                  onPressed: () {
                    double width = maxWidthController.text.isNotEmpty
                        ? double.parse(maxWidthController.text)
                        : null;
                    double height = maxHeightController.text.isNotEmpty
                        ? double.parse(maxHeightController.text)
                        : null;
                    int quality = qualityController.text.isNotEmpty
                        ? int.parse(qualityController.text)
                        : null;
                    onPick(width, height, quality);
                    Navigator.of(context).pop();
                  }),
            ],
          );
        });
  }
}

typedef void OnPickImageCallback(
    double maxWidth, double maxHeight, int quality);

class AspectRatioVideo extends StatefulWidget {
  AspectRatioVideo(this.controller);

  final VideoPlayerController controller;

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

class AspectRatioVideoState extends State<AspectRatioVideo> {
  VideoPlayerController get controller => widget.controller;
  bool initialized = false;

  void _onVideoControllerUpdate() {
    if (!mounted) {
      return;
    }
    if (initialized != controller.value.initialized) {
      initialized = controller.value.initialized;
      setState(() {});
    }
  }

  @override
  void initState() {
    super.initState();
    controller.addListener(_onVideoControllerUpdate);
  }

  @override
  void dispose() {
    controller.removeListener(_onVideoControllerUpdate);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (initialized) {
      return Center(
        child: AspectRatio(
          aspectRatio: controller.value?.aspectRatio,
          child: VideoPlayer(controller),
        ),
      );
    } else {
      return Container();
    }
  }
}

Use this package as a library

1. Depend on it

将此添加到包的pubspec.yaml文件中:


dependencies:
  image_picker: ^0.6.7+3

2. Install it

您可以从命令行安装软件包:

使用Flutter:


$ flutter pub get

另外,您的编辑器可能支持flutter pub get . 查看您的编辑器文档以了解更多信息.

3. Import it

现在,在Dart代码中,您可以使用:


import 'package:image_picker/image_picker.dart';
  
Popularity:
描述该程序包相对于其他程序包的受欢迎程度. [更多]
100
Health:
从静态分析得出的代码运行状况. [更多]
100
Maintenance:
反映出包装的整洁和最新状态. [更多]
100
Overall:
以上的加权分数. [更多]
100
了解有关得分的更多信息.

我们在2020年7月2日对该程序包进行了分析,并在下面提供了得分,详细信息和建议. using: 分析已完成,状态使用以下命令 :

  • 飞镖:2.8.4
  • 网页:0.13.13
  • 颤振:1.17.5

Analysis suggestions

软件包不支持Flutter平台Linux

由于导入路径[package:image_picker / image_picker.dart]声明支持以下平台:android,ios

软件包不支持Flutter平台macOS

由于导入路径[package:image_picker / image_picker.dart]声明支持以下平台:android,ios

软件包不支持Flutter平台Web

由于导入路径[package:image_picker / image_picker.dart]声明支持以下平台:android,ios

软件包不支持Flutter平台窗口

由于导入路径[package:image_picker / image_picker.dart]声明支持以下平台:android,ios

Package not compatible with SDK dart

由于导入路径[image_picker]在要求为null的软件包中.

Dependencies

Package Constraint Resolved Available
直接依赖
Dart SDK > = 2.1.0 <3.0.0
flutter 0.0.0
flutter_plugin_android_lifecycle ^1.0.2 1.0.8
image_picker_platform_interface ^1.1.0 1.1.0
传递依存关系
charcode 1.1.3
collection 1.14.12 1.14.13
http 0.12.1
http_parser 3.1.4
meta 1.1.8
path 1.7.0
plugin_platform_interface 1.0.2
sky_engine 0.0.99
source_span 1.7.0
string_scanner 1.0.5
term_glyph 1.1.0
typed_data 1.1.6 1.2.0
vector_math 2.0.8
开发依赖
e2e ^0.2.1
flutter_test
pedantic ^1.8.0 1.9.0 1.9.1
video_player ^0.10.3

by  ICOPY.SITE