Возможность задействовать камеру существует во многих приложениях, и мы все регулярно пользуемся ею. Во Flutter мы можем реализовать работу с камерой с помощью двух официальных плагинов:
Между ними – заметная разница, и использовать их стоит по ситуации:
camera
позволяет взаимодействовать с доступными устройству камерами из вашего приложения и выводить изображение в виджет. Хорошо подходит под задачи, когда надо "кастомизировать" работу камеры под приложение.image-picker
запускает приложение камеры и возвращает объект типаFile
(изображение или видеофайл, выбранный пользователем) в ваше приложение. Такжеimage-picker
дает возможность выбора файла из имеющихся на устройстве, при этом, как и в случае камеры, запускается отдельное приложение, после чего в ваше приложение возвращается выбранный объект.
Здесь можно посмотреть исходники.
camera
1. Добавляем плагин в наш проект по инструкции
Дополнительные настройки для ОС
iOS
Добавьте следующие строки в ios/Runner/Info.plist
:
<key>NSCameraUsageDescription</key>
<string>Access to Camera</string>
<key>NSMicrophoneUsageDescription</key>
<string>Access to Microphone</string>
Android
Убедить, что минимальная версия Android sdk в файле android/app/build.gradle
21.
minSdkVersion 21
Все необходимые разрешения будут запрошены при запуске приложения
Работа на эмуляторах
В случае IOS мы не можем проверить работу камеры на эмуляторе, нужно "живое" устройство.
Android генерирует некий mock (см. изображение ниже), который заменяет то, что видит объектив камеры.
В настройках эмулятора выбираем Advanced Settings и для задней камеры ставим VirtualScene
.
Перезапускаем эмулятор. Теперь камера "показывает" виртуальную комнату, по которой можно передвигать с помощью мыши и wasd.
Спасибо Tonn_Tamerlan за наводку.
2. Переходим к коду. Сначала получаем все доступные камеры с помощью функции availableCameras
.
final cameras = await availableCameras();
Данная функция вернет массив описаний (List<CameraDescription>
) доступных камер, где каждый элемент будет содержать имя камеры (это может быть просто индекс), тип (задняя, фронтальная, внешняя) и угол, на который надо повернуть фотографию, чтобы она отображалась в своей ориентации.
Для управления камерой нам нужен объект-контроллер типа CameraController
, для определения которого надо указать одно из полученных описаний камеры и разрешение (низкое, среднее, высокое).
void _setCameraController(CameraDescription cameraDescription) async {
_controller = CameraController(cameraDescription, ResolutionPreset.medium);
...
await _controller.initialize();
...
if (mounted) {
setState(() {});
}
}
Далее инициализируем контроллер и после того, как убедимся, что виджет "жив", обновляем состояние этого виджета. (текст функции)
Передаем инициализированный контроллер в виджет CameraPreview
AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: CameraPreview(_controller))
В основе CameraPreview
лежит виджет Texture
, отвечающий за отображение картинки с камеры. Его размеры определяются родителем, поэтому хорошо подход виджет AspectRatio
, определяющий размер дочернего элемента в определенном соотношении сторон. Соотношение мы получаем из контроллера _controller.value.aspectRatio
. В результате в интерфейсе получаем картинку в интерфейсе
3. Теперь мы можем сделать фотоснимок или снять видео.
а. Делаем фотографию (текст функции) с помощью метода takePicture(String path)
. Он делает снимок и сохраняет по указанному пути.
Future<void> _takePhoto(BuildContext context) async {
...
await _controller.takePicture(filePath);
...
}
Чтобы получить путь нам необходим официальный плагин path_provider и его метод getApplicationDocumentsDirectory
, который вернет приватную директорию. Далее определяем имя директории по вкусу, если надо создаем ее, и выбираем имя файла:
final Directory extDir = await getApplicationDocumentsDirectory();
final String dirPath = '${extDir.path}/Pictures/flutter_camera';
await Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${_getTimestamp()}.jpg';
Перед тем, как делать снимок, желательно проверить, что контроллер инициализирован и уже не делается фотография.
if (!_controller.value.isInitialized) {
return null;
}
...
if (_controller.value.isTakingPicture) {
return null;
}
Снимок сделан, у нас есть путь к нему, хорошо бы посмотреть. С помощью стандартного виджета Image
, объекта File
и пути к файлу выводим картинку на экран.
Image.file(File(filePath))
б. При записи видео (текст функции) нам понадобятся две функции: startVideoRecording(String filePath)
и stopVideoRecording()
.
Future<void> _startVideoRecording() async {
...
await _controller.startVideoRecording(filePath);
...
}
Future<void> _stopVideoRecording(BuildContext context) async {
...
await _controller.stopVideoRecording();
...
}
startVideoRecording
пишет видео и сохраняет по указанному пути (полученному по такому же принципу, как и с фотографией), stopVideoRecording
же просто завершает процесс записи. Перед началом записи следует убедиться, что съемка уже не идет.
if (_controller.value.isRecordingVideo) {
return null;
}
В результате у нас есть сохраненное видео и путь к нему. Для его проигрывания понадобится плагин video_player. Весь код, связанный с проигрыванием видео, вынесен в отдельный файл.
image-picker
1. Добавляем плагин в наш проект по инструкции
Дополнительные настройки для ОС
iOS
Добавьте следующие строки в ios/Runner/Info.plist
:
<key>NSCameraUsageDescription</key>
<string>Access to Camera</string>
<key>NSMicrophoneUsageDescription</key>
<string>Access to Microphone</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Access to PhotoLibrary</string>
Работа на эмуляторах
В IOS мы не можем проверить работу камеры на эмуляторе, нужно "живое" устройство.
2. image-picker
использует стандартное приложение для создания фото/видео или просмотра файлов. Для запуска нужного приложения необходимо воспользоваться функцией pickImage
для фото или pickVideo
и указать параметр source (источник).
...
final File video = await ImagePicker.pickVideo(source: ImageSource.camera);
final File photo = await ImagePicker.pickImage(source: ImageSource.gallery);
// для pickImage можно еще указать максимальные показатели ширины и высоты, иначе изображение вернется в оригинальном размере
...
Выбранный файл получает наше приложение, но если ничего не было выбрано, то вернется null
. Для показа картинки и видео используем те же подходы, что и в случае плагина camera
. Для изображений виджет Image
— в этот раз не надо оборачивать в File
, так как мы изначально получили объект этого типа.
Image.file(photo)
Для видео плагин video_player. Весь код, связанный с проигрыванием видео, вынесен в отдельный файл.
Заключение
Как вы успели заметить, image-picker
заметно проще в использовании и прекрасно подходит в тех случаях, когда просто надо передать изображение или видео приложению. camera
же предоставляет нам все необходимые возможности для кастомизации работы пользователя с камерой в вашем приложении.
Спасибо, что прочитали!