我的Flutter应用程序中存在以下问题:
为了使image_picker
的“取消”按钮正常工作,我需要能够在用户按下image_picker Plugin内的“取消”按钮时就打开Navigate.pop()。
此image_picker-Cancel问题的主要问题是:如何在小部件的构建器中向后导航(即Navigator.pop(context)
)?
以下引发错误:
Widget _cancelBtnPressedWidget(BuildContext context) {
Navigator.pop(context);
}
我知道Widget应该return
。因此,可以伪返回某些东西-但实际上将Navigator.pop()保留为Widget内部的主要动作? (最好是自动调用,而无需额外的用户交互)...
从上面的代码中,错误提示:
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)
。
下面是上述要求的详细说明:
实际上,我希望用户一按image_picker
Plugin的用法就按下Navigator.pop()。
我意识到snapshot.hashCode
更改是一种检测取消按钮是否被用户按下的方法。因此,如果用户按下该“取消”按钮,我只想将navigation.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);
},
)
],
);
}
答案 0 :(得分:0)
在我看来,您似乎根本没有捕获点击。对我来说,我将在_cancelBtnPressedWidget
中返回一个按钮,并在onPressed调用弹出窗口中返回
答案 1 :(得分: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();
}
}