#image #flutter #dart
#изображение #flutter #dart
Вопрос:
Я хочу отображать загрузочный виджет при сжатии выбранного изображения. Я использую пакет «image.dart» для выбора изображения с помощью ImagePicker.getImage().
Затем я хочу отобразить загрузочный виджет во время сжатия изображения, а по завершении отобразить сжатое изображение.
Мой код в принципе работает, мой загрузочный виджет классный (спасибо spinkit), я могу выбрать любое изображение, сжать его и отобразить новое, но во время сжатия изображения происходит небольшая остановка (2-3 секунды).
Итак, я пытаюсь установить загрузочный виджет, чтобы пользователь не паниковал и не нажимал 10 000 раз, чтобы выбрать нужное изображение, но я пока не совсем освоился с асинхронным кодом.
Вот мой код :
import 'package:image/image.dart' as Img;
@override
Widget build(BuildContext context) {
if (loading == true) {
return LoadingScreen();
} else {
return Scaffold(
backgroundColor: Colors.brown[300],
body: Column(
children: [
SizedBox(
height: 50,
),
RaisedButton(
child: Text('Select an image'),
onPressed: () async {
await getImage();
// You can see here that I'm trying to trigger the loading widget
setState(() {
loading = true;
});
compressImage();
// And I want to disable the loading widget here, after the compression
setState(() {
loading = false;
});
},
),
SizedBox(
height: 10,
),
pickedImage != null ? printSelectedImage() : Center(child: Text('Please select an image')),
],
),
);
}
}
getImage() async {
pickedFile = await picker.getImage(source: ImageSource.gallery);
}
compressImage() async {
Img.Image selectedImage = Img.decodeJpg(File(pickedFile.path).readAsBytesSync());
if (selectedImage.width > selectedImage.height) {
Img.Image compressedImage = Img.copyResize(selectedImage, width: 500);
File(pickedFile.path).writeAsBytesSync(Img.encodePng(compressedImage));
} else {
Img.Image compressedImage = Img.copyResize(selectedImage, height: 500);
File(pickedFile.path).writeAsBytesSync(Img.encodePng(compressedImage));
}
if (pickedFile.path != null) {
setState(() {
pickedImage = pickedFile.path;
});
}
}
Но результат тот же, экран по-прежнему застревает в селекторе файлов во время сжатия, а затем напрямую отображает сжатое изображение.
Я начал изучать dart / Flutter 2 недели назад, поэтому мне не хватает некоторых фундаментальных принципов языка dart? Я не вижу чего-то очевидного?
Спасибо за чтение
Ответ №1:
Создание чего-либо async
не перемещает это в какой-то волшебный фоновый поток. Dart использует изолированные объекты, которые в основном являются контекстом выполнения, в котором может выполняться код dart. У Flutter есть единственный изолят, который запускает ваше приложение, если вы выполняете в нем слишком много работы, ваше приложение замедляется или пропускает кадры.
Вы можете создавать другие изоляты для выполнения вычислений и разгрузки работы, а также обмениваться данными между изолятами, передавая сообщения с примитивным содержимым туда и обратно. Недостаток Flutter в том, что другие изоляты не имеют доступа к плагинам Flutter, поэтому многие вещи там не работают. Есть способы обойти это, но они довольно сложны.
Самый простой способ запустить изоляцию — это compute(callback, message)
функция.
Создайте изолированный файл, запустите
callback
этот изолированный файл, передав егоmessage
и
(в конечном итоге) верните значение, возвращенноеcallback
.
Я не уверен, что image/image.dart
библиотека использует плагин или какие-то другие функции, которые недоступны ( dart:ui
например), вы можете попробовать загрузить сжатие изображения в обратный вызов. Если произойдет сбой с помощью MissingPluginException
или чего-то подобного, то это не сработает. Помните, вы можете передавать только примитивные сообщения, поэтому вы не можете указывать путь pickedFile
, только передавать в качестве аргумента.
Однако для вашей проблемы может быть более простое решение. Средство выбора изображений принимает параметры для максимальной ширины / высоты и качества. Однако, если вам нужно, чтобы изображение было закодировано в формате PNG, вам нужно создать комплексное решение самостоятельно.
Комментарии:
1. Но займет ли средство выбора изображений больше времени, если я отправлю ему изображение нужного мне качества?
2. После беглого просмотра здесь эти примитивы могут передавать друг другу значения null, num, bool, double или String. Так что я все равно не смог бы вернуть все изображение?
3. Вы бы выбрали изображение в основном изолированном файле, а затем сжали его в compute, передав path в качестве аргумента. Средство выбора изображения не займет больше времени, если вы передадите размер в качестве начального аргумента.