image_picker取消:Flutter的Widget构建器中的Navigation.pop

问题描述 投票:0回答:2

我的Flutter App中有以下问题:

为了使image_picker取消按钮正常工作,我需要能够在用户按下image_picker Plugin内的取消按钮时Navigate.pop()。

这个image_picker-Cancel问题的主要问题是:如何在Widget的构建器中导航回来(即Navigator.pop(context))?

以下引发错误:

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

我知道Widget应该是return的东西。因此可以伪返回一些东西 - 但实际上将Navigator.pop()保持为Widget中的主要动作??? (最好,在没有额外用户交互的情况下自动调用)......

从上面的代码,错误sais:

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-change是检测取消按钮被用户按下的一种方法。因此,如果用户按下取消按钮,我只想将navigate.pop带回到我来自的地方;)...我不想再显示或将用户保留在Widget中,但立即返回到最初Navigate.pushed的视图。

这是进行图像查找的图像选择器部分 - 以及取消处理(即_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

添加在:

我试图添加一个确认对话框(即询问用户“你真的要取消”)。

现在,上述错误消失了。然而,现在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);
        },
      )
    ],
  );
}
build flutter widget picker navigator
2个回答
0
投票

对我来说,似乎你根本没有抓住点击。对我来说,我会在_cancelBtnPressedWidget中返回一个按钮,并在onPressed中调用pop。


0
投票

我终于找到了答案:

实际上,我能够进行确认对话,在那里我能够放置必要的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();
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.