Flutter - 从 gallery/camera 中选取图像不会更新保存选取的图像预览的容器
Flutter - picking an image from gallery/camera doesn't update the container that holds the picked image preview
我正在开发一个允许用户编写 post(类似于 facebook 的添加 post)的屏幕,用户可以在其中从图库中选择图片并可以在一个预览容器,问题是在我选择图像后预览不会立即更新,我必须离开屏幕并返回查看预览,我添加了屏幕截图以进一步解释,我还使用向上滑动面板作为底页,让用户能够选择媒体类型(图像、视频、音频...)。
使用的依赖项:
sliding_up_panel: ^1.0.2
image_picker:^0.6.6+5
这是我的完整代码:
MediaFilesServices mediaFilesServices = MediaFilesServices();
PanelController _panelController = new PanelController();
String mediaFileType = "NONE";
PickedFile _image;
final ImagePicker imagePicker = ImagePicker();
class AddPostScreen extends StatefulWidget {
@override
_AddPostScreenState createState() => _AddPostScreenState();
}
class _AddPostScreenState extends State<AddPostScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: SafeArea(
child: Container(
margin: const EdgeInsets.only(top: 20), child: AddPostBody()),
),
);
}
}
class AddPostBody extends StatefulWidget {
@override
_AddPostBodyState createState() => _AddPostBodyState();
}
class _AddPostBodyState extends State<AddPostBody> {
@override
Widget build(BuildContext context) {
return SlidingUpPanel(
padding: EdgeInsets.only(top: 12, left: 12, right: 12),
minHeight: 100,
maxHeight: 310,
backdropEnabled: true,
slideDirection: SlideDirection.UP,
isDraggable: true,
controller: _panelController,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24.0),
topRight: Radius.circular(24.0),
),
panel: ExpandedPanelBody(),
collapsed: collapsedPanelBody(),
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(right: 14.0, left: 14, top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
InkResponse(
onTap: () {
Navigator.pop(context);
},
child: Icon(CupertinoIcons.arrow_left)),
SizedBox(
width: 14,
),
Text('Add post'),
Spacer(),
ElevatedButton(
onPressed: () async {},
style: ButtonStyle(
shadowColor:
MaterialStateProperty.all<Color>(UIColors.primary_a),
backgroundColor:
MaterialStateProperty.all<Color>(UIColors.primary_a),
),
child: Text('share'),
)
],
),
),
SizedBox(
height: 18,
),
TextField(
maxLines: null,
keyboardType: TextInputType.multiline,
controller: _addPostController,
cursorColor: UIColors.primary_a,
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(horizontal: 16.0, vertical: 15.0),
border: InputBorder.none,
hintText: 'Say something...',
),
),
SizedBox(
height: 20,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 3),
decoration: BoxDecoration(
color: UIColors.primaryTextFieldBackground.withAlpha(3),
),
child: TextField(
maxLines: 1,
controller: _addPostLocationController,
cursorColor: UIColors.primary_a,
style: TextStyle(color: UIColors.primary_a),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(horizontal: 16.0, vertical: 15.0),
border: InputBorder.none,
hintText: 'drop your location',
prefixIcon: Icon(
CupertinoIcons.location_north_line_fill,
color: UIColors.primary_a,
size: 22,
),
),
),
),
SizedBox(
height: 14,
),
buildImageMedia(_image)
],
),
);
}
}
class ExpandedPanelBody extends StatefulWidget {
@override
_ExpandedPanelBodyState createState() => _ExpandedPanelBodyState();
}
class _ExpandedPanelBodyState extends State<ExpandedPanelBody> {
_imgFromCamera() async {
PickedFile image = await imagePicker.getImage(
source: ImageSource.camera, imageQuality: 100);
setState(() {
_image = image;
});
mediaFileType = "IMAGE";
}
_imgFromGallery() async {
PickedFile image = await imagePicker.getImage(
source: ImageSource.gallery, imageQuality: 100);
setState(() {
_image = image;
});
mediaFileType = "IMAGE";
}
@override
Widget build(BuildContext context) {
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (context) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text('Photo Library'),
onTap: () {
setState(() {
_imgFromGallery();
});
Navigator.of(context).pop();
}),
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () async {
await _imgFromCamera();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
return Container(
margin: EdgeInsets.only(bottom: 13.0),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.all(Radius.circular(64.0)),
),
margin: EdgeInsets.only(left: 180.0, right: 180.0, bottom: 10.0),
height: 6.0,
),
ListTile(
onTap: () {},
leading: Icon(
CupertinoIcons.plus_circle,
color: UIColors.primary_a,
),
title: Text(
'upload media',
style: TextStyle(
color: UIColors.primary_a, fontWeight: FontWeight.w300),
),
),
ListTile(
onTap: () {
_showPicker(context);
},
leading: Icon(
FeatherIcons.image,
color: Colors.black87,
),
title: Text(
'picture',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
FeatherIcons.film,
color: Colors.black87,
),
title: Text(
'video',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
FeatherIcons.headphones,
color: Colors.black87,
),
title: Text(
'audio',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
FeatherIcons.video,
color: UIColors.primary_a,
),
title: Text(
'go Live',
style: TextStyle(
color: UIColors.primary_a, fontWeight: FontWeight.w300),
),
),
],
),
);
}
}
Widget collapsedPanelBody() {
return Container(
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.all(Radius.circular(64.0)),
),
margin: EdgeInsets.only(left: 180.0, right: 180.0, bottom: 10.0),
height: 6.0,
),
ListTile(
onTap: () {
_panelController.open();
},
leading: Icon(
CupertinoIcons.plus_circle,
color: UIColors.primary_a,
),
title: Text(
'upload media',
style: TextStyle(
color: UIColors.primary_a, fontWeight: FontWeight.w300),
),
),
],
),
);
}
Widget buildImageMedia(PickedFile imgFilePreview) {
return Container(
margin: EdgeInsets.only(right: 14.0, left: 14),
child: FractionallySizedBox(
widthFactor: 1.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(12.0),
child: Container(
height: 300,
decoration: BoxDecoration(
color: UIColors.notSelectedColor,
image: DecorationImage(
image: imgFilePreview == null
? Image.file(File("assets/images/empty.png")).image
: Image.file(File(imgFilePreview.path)).image,
fit: BoxFit.cover),
)),
),
),
);
}
我知道问题出在哪里了。希望你不介意我改变了一些东西,无状态小部件可以用来代替有状态小部件,因为你不需要管理它们中的任何状态。
我已将您的 AddPostScreen 更改为 StatelessWidget,但您可以根据需要将其更改回 StatefulWidget。
MediaFilesServices mediaFilesServices = MediaFilesServices();
PanelController _panelController = new PanelController();
String mediaFileType = "NONE";
class AddPostScreen extends StatelessWidget {
const AddPostScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: SafeArea(
child: Container(
margin: const EdgeInsets.only(top: 20), child: AddPostBody()),
),
);
}
}
请注意我声明的新 PickedFile 变量和我添加的方法。我留下评论进一步解释。
class AddPostBody extends StatefulWidget {
@override
_AddPostBodyState createState() => _AddPostBodyState();
}
class _AddPostBodyState extends State<AddPostBody> {
/// This is the variable that will hold the image the user has selected and is passed to the [buildImageMedia] Widget method
PickedFile userSelectedImage;
/// This is a callback method that will assign the value of [userSelectedImage]
/// from the user's image choice in the ExpandedPanelBody class
void selectedImageHandler(PickedFile selectedImage) {
setState(() {
userSelectedImage = selectedImage;
});
}
@override
Widget build(BuildContext context) {
return SlidingUpPanel(
padding: EdgeInsets.only(top: 12, left: 12, right: 12),
minHeight: 100,
maxHeight: 310,
backdropEnabled: true,
slideDirection: SlideDirection.UP,
isDraggable: true,
controller: _panelController,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24.0),
topRight: Radius.circular(24.0),
),
panel: ExpandedPanelBody(selectedImageHandler),
collapsed: collapsedPanelBody(),
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(right: 14.0, left: 14, top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
InkResponse(
onTap: () {
Navigator.pop(context);
},
child: Icon(CupertinoIcons.arrow_left)),
SizedBox(
width: 14,
),
Text('Add post'),
Spacer(),
ElevatedButton(
onPressed: () async {},
style: ButtonStyle(
shadowColor:
MaterialStateProperty.all<Color>(Colors.orangeAccent),
backgroundColor:
MaterialStateProperty.all<Color>(Colors.orangeAccent),
),
child: Text('share'),
)
],
),
),
SizedBox(
height: 18,
),
TextField(
maxLines: null,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(horizontal: 16.0, vertical: 15.0),
border: InputBorder.none,
hintText: 'Say something...',
),
),
SizedBox(
height: 20,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 3),
decoration: BoxDecoration(
color: Colors.blueAccent,
),
child: TextField(
maxLines: 1,
style: TextStyle(color: Colors.black),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(horizontal: 16.0, vertical: 15.0),
border: InputBorder.none,
hintText: 'drop your location',
prefixIcon: Icon(
CupertinoIcons.location_north_line_fill,
color: Colors.red,
size: 22,
),
),
),
),
SizedBox(
height: 14,
),
buildImageMedia(userSelectedImage)
],
),
);
}
}
对于 ExpandedPanelBody class,我从 [_imgFromCamera] 和 [_imgFromGallery] 方法中删除了 setState 调用,而是使用 class 构造函数中声明的 [triggerSelectedImage] 函数,它将在 AddPostBody class 中设置 [userSelectedImage] 的状态并显示用户的图像选择
class ExpandedPanelBody extends StatefulWidget {
final Function(PickedFile) triggerSelectedImage;
ExpandedPanelBody(this.triggerSelectedImage);
@override
_ExpandedPanelBodyState createState() => _ExpandedPanelBodyState();
}
class _ExpandedPanelBodyState extends State<ExpandedPanelBody> {
/// The instance of ImagePicker is declared here, where it is used
final ImagePicker imagePicker = ImagePicker();
_imgFromCamera() async {
PickedFile image = await imagePicker.getImage(
source: ImageSource.camera, imageQuality: 100);
widget.triggerSelectedImage(image);
mediaFileType = "IMAGE";
}
_imgFromGallery() async {
PickedFile image = await imagePicker.getImage(
source: ImageSource.gallery, imageQuality: 100);
widget.triggerSelectedImage(image);
mediaFileType = "IMAGE";
}
@override
Widget build(BuildContext context) {
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (context) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text('Photo Library'),
onTap: () {
setState(() {
_imgFromGallery();
});
Navigator.of(context).pop();
}),
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () async {
await _imgFromCamera();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
return Container(
margin: EdgeInsets.only(bottom: 13.0),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.all(Radius.circular(64.0)),
),
margin: EdgeInsets.only(left: 180.0, right: 180.0, bottom: 10.0),
height: 6.0,
),
ListTile(
onTap: () {},
leading: Icon(
CupertinoIcons.plus_circle,
color: Colors.red,
),
title: Text(
'upload media',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.w300),
),
),
ListTile(
onTap: () {
_showPicker(context);
},
leading: Icon(
Icons.account_balance,
color: Colors.black87,
),
title: Text(
'picture',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
Icons.account_balance,
color: Colors.black87,
),
title: Text(
'video',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
Icons.account_balance,
color: Colors.black87,
),
title: Text(
'audio',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
Icons.account_balance,
color: Colors.orangeAccent,
),
title: Text(
'go Live',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.w300),
),
),
],
),
);
}
}
其他Widget方法(collapsedPanelBody & buildImageMedia)保持不变。
解决方案是使用回调方法。
我正在开发一个允许用户编写 post(类似于 facebook 的添加 post)的屏幕,用户可以在其中从图库中选择图片并可以在一个预览容器,问题是在我选择图像后预览不会立即更新,我必须离开屏幕并返回查看预览,我添加了屏幕截图以进一步解释,我还使用向上滑动面板作为底页,让用户能够选择媒体类型(图像、视频、音频...)。
使用的依赖项:
sliding_up_panel: ^1.0.2
image_picker:^0.6.6+5
这是我的完整代码:
MediaFilesServices mediaFilesServices = MediaFilesServices();
PanelController _panelController = new PanelController();
String mediaFileType = "NONE";
PickedFile _image;
final ImagePicker imagePicker = ImagePicker();
class AddPostScreen extends StatefulWidget {
@override
_AddPostScreenState createState() => _AddPostScreenState();
}
class _AddPostScreenState extends State<AddPostScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: SafeArea(
child: Container(
margin: const EdgeInsets.only(top: 20), child: AddPostBody()),
),
);
}
}
class AddPostBody extends StatefulWidget {
@override
_AddPostBodyState createState() => _AddPostBodyState();
}
class _AddPostBodyState extends State<AddPostBody> {
@override
Widget build(BuildContext context) {
return SlidingUpPanel(
padding: EdgeInsets.only(top: 12, left: 12, right: 12),
minHeight: 100,
maxHeight: 310,
backdropEnabled: true,
slideDirection: SlideDirection.UP,
isDraggable: true,
controller: _panelController,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24.0),
topRight: Radius.circular(24.0),
),
panel: ExpandedPanelBody(),
collapsed: collapsedPanelBody(),
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(right: 14.0, left: 14, top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
InkResponse(
onTap: () {
Navigator.pop(context);
},
child: Icon(CupertinoIcons.arrow_left)),
SizedBox(
width: 14,
),
Text('Add post'),
Spacer(),
ElevatedButton(
onPressed: () async {},
style: ButtonStyle(
shadowColor:
MaterialStateProperty.all<Color>(UIColors.primary_a),
backgroundColor:
MaterialStateProperty.all<Color>(UIColors.primary_a),
),
child: Text('share'),
)
],
),
),
SizedBox(
height: 18,
),
TextField(
maxLines: null,
keyboardType: TextInputType.multiline,
controller: _addPostController,
cursorColor: UIColors.primary_a,
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(horizontal: 16.0, vertical: 15.0),
border: InputBorder.none,
hintText: 'Say something...',
),
),
SizedBox(
height: 20,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 3),
decoration: BoxDecoration(
color: UIColors.primaryTextFieldBackground.withAlpha(3),
),
child: TextField(
maxLines: 1,
controller: _addPostLocationController,
cursorColor: UIColors.primary_a,
style: TextStyle(color: UIColors.primary_a),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(horizontal: 16.0, vertical: 15.0),
border: InputBorder.none,
hintText: 'drop your location',
prefixIcon: Icon(
CupertinoIcons.location_north_line_fill,
color: UIColors.primary_a,
size: 22,
),
),
),
),
SizedBox(
height: 14,
),
buildImageMedia(_image)
],
),
);
}
}
class ExpandedPanelBody extends StatefulWidget {
@override
_ExpandedPanelBodyState createState() => _ExpandedPanelBodyState();
}
class _ExpandedPanelBodyState extends State<ExpandedPanelBody> {
_imgFromCamera() async {
PickedFile image = await imagePicker.getImage(
source: ImageSource.camera, imageQuality: 100);
setState(() {
_image = image;
});
mediaFileType = "IMAGE";
}
_imgFromGallery() async {
PickedFile image = await imagePicker.getImage(
source: ImageSource.gallery, imageQuality: 100);
setState(() {
_image = image;
});
mediaFileType = "IMAGE";
}
@override
Widget build(BuildContext context) {
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (context) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text('Photo Library'),
onTap: () {
setState(() {
_imgFromGallery();
});
Navigator.of(context).pop();
}),
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () async {
await _imgFromCamera();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
return Container(
margin: EdgeInsets.only(bottom: 13.0),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.all(Radius.circular(64.0)),
),
margin: EdgeInsets.only(left: 180.0, right: 180.0, bottom: 10.0),
height: 6.0,
),
ListTile(
onTap: () {},
leading: Icon(
CupertinoIcons.plus_circle,
color: UIColors.primary_a,
),
title: Text(
'upload media',
style: TextStyle(
color: UIColors.primary_a, fontWeight: FontWeight.w300),
),
),
ListTile(
onTap: () {
_showPicker(context);
},
leading: Icon(
FeatherIcons.image,
color: Colors.black87,
),
title: Text(
'picture',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
FeatherIcons.film,
color: Colors.black87,
),
title: Text(
'video',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
FeatherIcons.headphones,
color: Colors.black87,
),
title: Text(
'audio',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
FeatherIcons.video,
color: UIColors.primary_a,
),
title: Text(
'go Live',
style: TextStyle(
color: UIColors.primary_a, fontWeight: FontWeight.w300),
),
),
],
),
);
}
}
Widget collapsedPanelBody() {
return Container(
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.all(Radius.circular(64.0)),
),
margin: EdgeInsets.only(left: 180.0, right: 180.0, bottom: 10.0),
height: 6.0,
),
ListTile(
onTap: () {
_panelController.open();
},
leading: Icon(
CupertinoIcons.plus_circle,
color: UIColors.primary_a,
),
title: Text(
'upload media',
style: TextStyle(
color: UIColors.primary_a, fontWeight: FontWeight.w300),
),
),
],
),
);
}
Widget buildImageMedia(PickedFile imgFilePreview) {
return Container(
margin: EdgeInsets.only(right: 14.0, left: 14),
child: FractionallySizedBox(
widthFactor: 1.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(12.0),
child: Container(
height: 300,
decoration: BoxDecoration(
color: UIColors.notSelectedColor,
image: DecorationImage(
image: imgFilePreview == null
? Image.file(File("assets/images/empty.png")).image
: Image.file(File(imgFilePreview.path)).image,
fit: BoxFit.cover),
)),
),
),
);
}
我知道问题出在哪里了。希望你不介意我改变了一些东西,无状态小部件可以用来代替有状态小部件,因为你不需要管理它们中的任何状态。
我已将您的 AddPostScreen 更改为 StatelessWidget,但您可以根据需要将其更改回 StatefulWidget。
MediaFilesServices mediaFilesServices = MediaFilesServices();
PanelController _panelController = new PanelController();
String mediaFileType = "NONE";
class AddPostScreen extends StatelessWidget {
const AddPostScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: SafeArea(
child: Container(
margin: const EdgeInsets.only(top: 20), child: AddPostBody()),
),
);
}
}
请注意我声明的新 PickedFile 变量和我添加的方法。我留下评论进一步解释。
class AddPostBody extends StatefulWidget {
@override
_AddPostBodyState createState() => _AddPostBodyState();
}
class _AddPostBodyState extends State<AddPostBody> {
/// This is the variable that will hold the image the user has selected and is passed to the [buildImageMedia] Widget method
PickedFile userSelectedImage;
/// This is a callback method that will assign the value of [userSelectedImage]
/// from the user's image choice in the ExpandedPanelBody class
void selectedImageHandler(PickedFile selectedImage) {
setState(() {
userSelectedImage = selectedImage;
});
}
@override
Widget build(BuildContext context) {
return SlidingUpPanel(
padding: EdgeInsets.only(top: 12, left: 12, right: 12),
minHeight: 100,
maxHeight: 310,
backdropEnabled: true,
slideDirection: SlideDirection.UP,
isDraggable: true,
controller: _panelController,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24.0),
topRight: Radius.circular(24.0),
),
panel: ExpandedPanelBody(selectedImageHandler),
collapsed: collapsedPanelBody(),
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(right: 14.0, left: 14, top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
InkResponse(
onTap: () {
Navigator.pop(context);
},
child: Icon(CupertinoIcons.arrow_left)),
SizedBox(
width: 14,
),
Text('Add post'),
Spacer(),
ElevatedButton(
onPressed: () async {},
style: ButtonStyle(
shadowColor:
MaterialStateProperty.all<Color>(Colors.orangeAccent),
backgroundColor:
MaterialStateProperty.all<Color>(Colors.orangeAccent),
),
child: Text('share'),
)
],
),
),
SizedBox(
height: 18,
),
TextField(
maxLines: null,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(horizontal: 16.0, vertical: 15.0),
border: InputBorder.none,
hintText: 'Say something...',
),
),
SizedBox(
height: 20,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 3),
decoration: BoxDecoration(
color: Colors.blueAccent,
),
child: TextField(
maxLines: 1,
style: TextStyle(color: Colors.black),
decoration: InputDecoration(
contentPadding:
EdgeInsets.symmetric(horizontal: 16.0, vertical: 15.0),
border: InputBorder.none,
hintText: 'drop your location',
prefixIcon: Icon(
CupertinoIcons.location_north_line_fill,
color: Colors.red,
size: 22,
),
),
),
),
SizedBox(
height: 14,
),
buildImageMedia(userSelectedImage)
],
),
);
}
}
对于 ExpandedPanelBody class,我从 [_imgFromCamera] 和 [_imgFromGallery] 方法中删除了 setState 调用,而是使用 class 构造函数中声明的 [triggerSelectedImage] 函数,它将在 AddPostBody class 中设置 [userSelectedImage] 的状态并显示用户的图像选择
class ExpandedPanelBody extends StatefulWidget {
final Function(PickedFile) triggerSelectedImage;
ExpandedPanelBody(this.triggerSelectedImage);
@override
_ExpandedPanelBodyState createState() => _ExpandedPanelBodyState();
}
class _ExpandedPanelBodyState extends State<ExpandedPanelBody> {
/// The instance of ImagePicker is declared here, where it is used
final ImagePicker imagePicker = ImagePicker();
_imgFromCamera() async {
PickedFile image = await imagePicker.getImage(
source: ImageSource.camera, imageQuality: 100);
widget.triggerSelectedImage(image);
mediaFileType = "IMAGE";
}
_imgFromGallery() async {
PickedFile image = await imagePicker.getImage(
source: ImageSource.gallery, imageQuality: 100);
widget.triggerSelectedImage(image);
mediaFileType = "IMAGE";
}
@override
Widget build(BuildContext context) {
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (context) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text('Photo Library'),
onTap: () {
setState(() {
_imgFromGallery();
});
Navigator.of(context).pop();
}),
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () async {
await _imgFromCamera();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
return Container(
margin: EdgeInsets.only(bottom: 13.0),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.all(Radius.circular(64.0)),
),
margin: EdgeInsets.only(left: 180.0, right: 180.0, bottom: 10.0),
height: 6.0,
),
ListTile(
onTap: () {},
leading: Icon(
CupertinoIcons.plus_circle,
color: Colors.red,
),
title: Text(
'upload media',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.w300),
),
),
ListTile(
onTap: () {
_showPicker(context);
},
leading: Icon(
Icons.account_balance,
color: Colors.black87,
),
title: Text(
'picture',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
Icons.account_balance,
color: Colors.black87,
),
title: Text(
'video',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
Icons.account_balance,
color: Colors.black87,
),
title: Text(
'audio',
style:
TextStyle(color: Colors.black87, fontWeight: FontWeight.w300),
),
),
ListTile(
leading: Icon(
Icons.account_balance,
color: Colors.orangeAccent,
),
title: Text(
'go Live',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.w300),
),
),
],
),
);
}
}
其他Widget方法(collapsedPanelBody & buildImageMedia)保持不变。 解决方案是使用回调方法。