Изображение не обновляется даже после использования setState в Flutter

#flutter #dart #state #setstate

#flutter #dart #состояние #setstate

Вопрос:

Я использую ImagePicker и пакет ImageCropper для выбора и обрезки изображения из галереи или захвата с помощью камеры. Все работает нормально, но выбранное изображение не обновляется в пользовательском интерфейсе даже после использования метода setState. Когда я снова нажимаю кнопку для выбора изображения, в пользовательском интерфейсе появляется ранее выбранное изображение. Я понятия не имею, что вызывает эту задержку.

Мой код класса обработки изображений

 class ImageProcess{
  File _image, croppedFile;
  final picker = ImagePicker();
  //Getting Image From Gallery Or Camera.
  File getImage(BuildContext context) {
    showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.all(Radius.circular(15))),
            content: Container(
                height: 250,
                width: 250,
                child: Row(
                  children: [
                    IconButton(
                        iconSize: 100,
                        icon: Icon(Icons.insert_photo),
                        onPressed: () async {
                          final pickedFile = await picker.getImage(
                              source: ImageSource.gallery,imageQuality: 20);
                          _image = File(pickedFile.path);
                        croppedFile = await _cropImage();
                          Navigator.of(context).pop(true);
                        }),
                    IconButton(
                        iconSize: 100,
                        icon: Icon(Icons.camera),
                        onPressed: () async {
                          final pickedFile =
                          await picker.getImage(source: ImageSource.camera,imageQuality: 20);
                          _image = File(pickedFile.path);
                       croppedFile =  await _cropImage();
                          Navigator.of(context).pop(true);
                        })
                  ],
                )),
          );
        });
    return croppedFile;
  }

  //Cropping image which has been retrieved from gallery or gallery.
  Future<File> _cropImage() async {
   return await ImageCropper.cropImage(
        sourcePath: _image.path,
        aspectRatioPresets: Platform.isAndroid
            ? [
          CropAspectRatioPreset.square,
        ]
            : [
          CropAspectRatioPreset.square,
        ],
        androidUiSettings: AndroidUiSettings(
            toolbarTitle: 'Product Image Cropper',
            toolbarColor: kDarkYellow,
            toolbarWidgetColor: Colors.white,
            initAspectRatio: CropAspectRatioPreset.square,
            lockAspectRatio: false),
        iosUiSettings: IOSUiSettings(
          title: 'Product Image Cropper',
        ));
  }
}
  

Код пользовательского интерфейса

 class AddItem extends StatefulWidget {
  @override
  _AddItemState createState() => _AddItemState();
}

class _AddItemState extends State<AddItem> {
  File croppedFile;
  ImageProcess im = new ImageProcess();
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
          backgroundColor: kVeryDarkBlue,
          body: SingleChildScrollView(
              child: Padding(
                padding: EdgeInsets.fromLTRB(20, 20, 20, 0),
                child: Column(
                  children: [
                    Container(
                        height: MediaQuery.of(context).size.height * 0.15,
                        width: MediaQuery.of(context).size.height * 0.15,
                        child: croppedFile == null
                            ? ClipOval(
                            child:
                            Image.asset('assets/images/image.png'))
                            : ClipOval(child: Image.file(croppedFile))),
                    RaisedButton(onPressed: () {
                        croppedFile= im.getImage(context);
                        setState(() {
                        });
                    },child: Text('Press'),)
                  ],
                ),
              ))),
    );
  }
}
  

Я перепробовал все возможные решения, которые пришли мне в голову.

Комментарии:

1. Вам нужно использовать Future в вашем методе getImage. Без него ваш setstate обновит пользовательский интерфейс, прежде чем вы получите изображение.

2. Можете ли вы показать мне пример.

Ответ №1:

Добавьте Future в свой метод getImage с некоторыми настройками.

 import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';

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,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: AddItem(),
    );
  }
}

class AddItem extends StatefulWidget {
  @override
  _AddItemState createState() => _AddItemState();
}

class _AddItemState extends State<AddItem> {
  File croppedFile;
  ImageProcess im = new ImageProcess();
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
          backgroundColor: Colors.blue,
          body: SingleChildScrollView(
              child: Padding(
            padding: EdgeInsets.fromLTRB(20, 20, 20, 0),
            child: Column(
              children: [
                Container(
                    height: MediaQuery.of(context).size.height * 0.15,
                    width: MediaQuery.of(context).size.height * 0.15,
                    child: croppedFile == null
                        ? ClipOval(
                            child: Image.asset('assets/images/image.png'))
                        : ClipOval(child: Image.file(croppedFile))),
                RaisedButton(
                  onPressed: () async {
                    // Add await here
                    croppedFile = await im.getImage(context);
                    setState(() {});
                  },
                  child: Text('Press'),
                )
              ],
            ),
          ))),
    );
  }
}

class ImageProcess {
  File _image, croppedFile;
  final picker = ImagePicker();
  //Getting Image From Gallery Or Camera.
  // now getImage is a future that wait for your choice.
  Future<File> getImage(BuildContext context) async {
    return await showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.all(Radius.circular(15))),
            content: Container(
                height: 250,
                width: 250,
                child: Row(
                  children: [
                    IconButton(
                        iconSize: 100,
                        icon: Icon(Icons.insert_photo),
                        onPressed: () async {
                          final pickedFile = await picker.getImage(
                              source: ImageSource.gallery, imageQuality: 20);
                          _image = File(pickedFile.path);
                          croppedFile = await _cropImage();
                          // croppedFile is the return of your ShowDialog
                          Navigator.of(context).pop(croppedFile);
                        }),
                    IconButton(
                        iconSize: 100,
                        icon: Icon(Icons.camera),
                        onPressed: () async {
                          final pickedFile = await picker.getImage(
                              source: ImageSource.camera, imageQuality: 20);
                          _image = File(pickedFile.path);
                          croppedFile = await _cropImage();
                          // croppedFile is the return of your ShowDialog
                          Navigator.of(context).pop(croppedFile);
                        })
                  ],
                )),
          );
        });
  }

  //Cropping image which has been retrieved from gallery or gallery.
  Future<File> _cropImage() async {
    return await ImageCropper.cropImage(
        sourcePath: _image.path,
        aspectRatioPresets: Platform.isAndroid
            ? [
                CropAspectRatioPreset.square,
              ]
            : [
                CropAspectRatioPreset.square,
              ],
        androidUiSettings: AndroidUiSettings(
            toolbarTitle: 'Product Image Cropper',
            toolbarColor: Colors.yellow,
            toolbarWidgetColor: Colors.white,
            initAspectRatio: CropAspectRatioPreset.square,
            lockAspectRatio: false),
        iosUiSettings: IOSUiSettings(
          title: 'Product Image Cropper',
        ));
  }
}
  

Ответ №2:

После настройки нескольких строк я выяснил, в чем была проблема.

Код для RaisedButton в пользовательском интерфейсе

 RaisedButton(
                  onPressed: () {
                    showDialog(
                        context: context,
                        builder: (context) {
                          return AlertDialog(
                            shape: RoundedRectangleBorder(
                                borderRadius:
                                    BorderRadius.all(Radius.circular(15))),
                            content: Container(
                                height: 250,
                                width: 250,
                                child: Row(
                                  children: [
                                    IconButton(
                                        iconSize: 100,
                                        icon: Icon(Icons.insert_photo),
                                        onPressed: () async {
                                          croppedFile =
                                              await im.getImageGallery();
                                          setState(() {});
                                          Navigator.pop(context);
                                        }),
                                    IconButton(
                                        iconSize: 100,
                                        icon: Icon(Icons.camera),
                                        onPressed: () async {
                                          croppedFile =
                                          await im.getImageCamera();
                                          setState(() {});
                                          Navigator.pop(context);
                                        })
                                  ],
                                )),
                          );
                        });
                  },
                  child: Text('Press'),
                )
  

Код для класса обработки изображений. Я разделил большую функцию на две вспомогательные функции.

   //Getting Image From Camera.
  Future<File> getImageCamera() async{
    final pickedFile = await picker.getImage(
        source: ImageSource.camera,imageQuality: 20);
    _image = File(pickedFile.path);
    return _cropImage();
  }
  //Getting Image From Gallery
  Future<File> getImageGallery() async{
    final pickedFile = await picker.getImage(
        source: ImageSource.gallery,imageQuality: 20);
    _image = File(pickedFile.path);
    return _cropImage();
  }