image_picker Отмена: Navigation.pop внутри конструктора виджетов для Flutter - PullRequest
0 голосов
/ 12 февраля 2019

У меня есть следующая проблема в приложении Flutter:

Чтобы кнопка отмены image_picker работала правильно, мне нужно было иметь возможность Navigate.pop () в тот момент, когда пользователь нажимает кнопку ОтменаКнопка внутри плагина image_picker .

Главный вопрос для этой проблемы image_picker-Cancel: Как мне вернуться назад (т.е. Navigator.pop(context)) внутри компоновщика виджета?

Следующее выдает ошибку:

  Widget _cancelBtnPressedWidget(BuildContext context) {
    Navigator.pop(context);
  }

Я знаю, что виджет должен return что-то.Следовательно, возможно ли псевдо-возвращать что-то, но на самом деле оставить Navigator.pop () в качестве основного действия внутри виджета ???(и лучше всего, автоматически вызывается без дополнительного взаимодействия с пользователем) ...

Из вышеприведенного кода возникает ошибка:

flutter: ══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown while notifying status listeners for AnimationController:
flutter: setState() or markNeedsBuild() called during build.
flutter: This Overlay widget cannot be marked as needing to build because the framework is already in the
flutter: process of building widgets. A widget can be marked as needing to be built during the build phase
flutter: only if one of its ancestors is currently building. This exception is allowed because the framework
flutter: builds parent widgets before children, which means a dirty descendant will always be built.
flutter: Otherwise, the framework might not visit this widget during this build phase.
flutter: The widget on which setState() or markNeedsBuild() was called was:
flutter:   Overlay-[LabeledGlobalKey<OverlayState>#b5c98](state: OverlayState#6a872(entries:
flutter:   [OverlayEntry#cd1e7(opaque: false; maintainState: false), OverlayEntry#43b81(opaque: false;
flutter:   maintainState: true), OverlayEntry#f0b49(opaque: false; maintainState: false),
flutter:   OverlayEntry#b9362(opaque: false; maintainState: true)]))
flutter: The widget which was currently being built when the offending call was made was:
flutter:   FutureBuilder<File>(dirty, state: _FutureBuilderState<File>#d3cac)

.

Здесь более подробноописание того, откуда вышло вышеупомянутое требование:

На самом деле, я хотел бы использовать Navigator.pop (), как только пользователь нажмет кнопку отмены, как для image_picker Plugin использование.

Я понял, что замена snapshot.hashCode - это один из способов обнаружить нажатие пользователем кнопки отмены.Поэтому, если пользователь нажимает эту кнопку «Отмена», я хотел бы сделать не более, чем navigate.pop, туда, откуда я пришел;) ... Я больше не хочу показывать или держать пользователя внутри виджета, но сразувернитесь к виду, который изначально был Navigate.pressed.

Здесь находится часть средства выбора изображения, которая выполняет поиск изображения и обработку Cancel (т.е. вызов _cancelBtnPressedWidget -Widget).

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

File _imageFile;
bool _pickImage = true;
int _hashy = 0;

@override
Widget build(BuildContext context) {
  if (_pickImage) {
    return FutureBuilder<File>(
      future: ImagePicker.pickImage(source: ImageSource.camera),
      builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
        if (snapshot.hasData) {
          _pickImage = false;
          _imageFile = snapshot.data;
          return _showImage(snapshot.data);
        } else {
          // when cancel is pressed, the hashCode changes...
          if ((_hashy != 0) && (snapshot.hashCode != _hashy)) {
            // when cancel pressed
            return _cancelBtnPressedWidget(context);
          }
          _hashy = snapshot.hashCode;
          return Scaffold(
            body: Center(
              child: Text('no image picker available'),
            ),
          );
        }
      },
    );
  } else {
    return _showImage(_imageFile);
  }
}
Widget _cancelBtnPressedWidget(BuildContext context) {
  // requires a return ..... How to overcome this requirement ????
  Navigator.pop(context);
}
Widget _showImage(File imgFile) {
  return Scaffold(
    body: SafeArea(
      child: Stack(
        alignment: AlignmentDirectional.topStart,
        children: <Widget>[
          Positioned(
            left: 0.0,
            bottom: 0.0,
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            child: Center(
              child: imgFile == null
                  ? Text('No image selected.')
                  : Image.file(imgFile),
            ),
          ),
         // more stacks ... not important here....
        ],
      ),
    ),
  );
}

Конечно, внутри pubspec.yaml вы добавляете необходимую зависимость:

dependencies:
  flutter:
    sdk: flutter
  image_picker: ^0.5.0+3

Надстройка:

Я пытался добавить подтверждение-dialog (т.е. спросить пользователя «Вы действительно хотите отменить»).

Теперь вышеприведенная ошибка исчезла.Однако теперь image_picker продолжает появляться снова и снова ... перезаписывая этот диалог.

Что я все еще делаю не так с ней ??

Widget _cancelBtnPressedWidget(BuildContext context) {
  return AlertDialog(
    title: Text('Camera Alert'),
    content: Text('Are you sure you want to cancel ?'),
    actions: <Widget>[
      FlatButton(
        child: Text('Close'),
        onPressed: () {
          Navigator.pop(context);
        },
      )
    ],
  );
}

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

Я наконец нашел ответ:

Действительно, я смог разместить диалоговое окно подтверждения, и там я смог разместить необходимые return Widget.

Теперь отмена дляimage_picker работает как положено!

Вот весь код:

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

class MyImagePickerView extends StatefulWidget {
  _MyImagePickerViewState createState() => _MyImagePickerViewState();
}

class _MyImagePickerViewState extends State<MyImagePickerView> {
  File _imageFile;
  bool _pickImage = true;
  int _hashy = 0;
  bool _cancelPressed = false;

  @override
  Widget build(BuildContext context) {
    if (_pickImage) {
      return FutureBuilder<File>(
        future: ImagePicker.pickImage(source: ImageSource.camera),
        builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
          if (snapshot.hasData) {
            _pickImage = false;
            _imageFile = snapshot.data;
            return _showImage(snapshot.data);
          } else {
            // when cancel is pressed, the hashCode changes...
            if ((_hashy != 0) && (snapshot.hashCode != _hashy)) {
              // when cancel pressed
              return _cancelBtnPressedWidget(context);
            }
            _hashy = snapshot.hashCode;
            return Scaffold(
              body: Center(
                child: Text('no image picker available'),
              ),
            );
          }
        },
      );
    } else {
      if (_cancelPressed) {
        return _showAlert();
      } else {
        return _showImage(_imageFile);
      }
    }
  }

  Widget _cancelBtnPressedWidget(BuildContext context) {
    _cancelPressed = true;
    _pickImage = false;
    return Scaffold(
      body: Center(
        child: Text('Press button to start.'),
      ),
    );
  }

  Widget _showImage(File imgFile) {
    StateContainerState container = StateContainer.of(context);
    return Scaffold(
      body: SafeArea(
        child: Stack(
          alignment: AlignmentDirectional.topStart,
          children: <Widget>[
            Positioned(
              left: 0.0,
              bottom: 0.0,
              width: MediaQuery.of(context).size.width,
              height: MediaQuery.of(context).size.height,
              child: Center(
                child: imgFile == null
                    ? Text('No image selected.')
                    : Image.file(imgFile),
              ),
            ),
            // more stacks ... not important here....
          ],
        ),
      ),
    );
  }

  Widget _showAlert() {
    return AlertDialog(
      title: Text('Camera Alert'),
      content: Text('Are you sure you want to cancel the Camera ?'),
      actions: <Widget>[
        FlatButton(
          child: Text('No'),
          onPressed: () {
            setState(() {
              _pickImage = true;
              _cancelPressed = false;
            });
          },
        ),
        FlatButton(
          child: Text('Yes'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ],
    );
  }

  @override
  void dispose() {
    _myController.dispose();
    super.dispose();
  }
}
0 голосов
/ 12 февраля 2019

Мне не кажется, что вы захватываете щелчок вообще.Для меня я бы вернул кнопку в _cancelBtnPressedWidget и в вызове onPressed pop.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...