file_picker - onPressed 不删除卡片也不刷新视图
file_picker - onPressed does not delete a card neither refresh the view
我正在使用 File_Picker.dart
我对我编写的功能之一有疑问。当我点击删除图标时,记录没有被删除,屏幕也没有刷新。我的意思是卡仍然显示。
另外,我正在尝试做的是能够一个一个地添加一个文件,而不删除之前选择的文件。但每次我单击调用“_openFileExplorer()”的按钮 'Open File picker' 时,先前选择的文件都会从屏幕上删除。我还没有找到如何阻止这种情况发生的方法。
如果您能帮我解决这个问题,我们将不胜感激。非常感谢。
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';
class FilePickerDemo extends StatefulWidget {
@override
_FilePickerDemoState createState() => _FilePickerDemoState();
}
class _FilePickerDemoState extends State<FilePickerDemo> {
//FirebaseStorage storage = FirebaseStorage.instance;
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
late String _fileName;
List<PlatformFile>? _paths;
bool _loadingPath = false;
bool _multiPick = true;
FileType _fileType = FileType.media;
/*
@override
void initState() {
super.initState();
Firebase.initializeApp();
}
*/
void _openPictureFileExplorer() async {
setState(() => _loadingPath = true);
/*
try{
var files = (await FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
))
?.files;
_paths = _paths!..addAll(files!.map((e) => e));
_loadingPath = false;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
*/
try {
_paths = (await FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
))
?.files;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
if (!mounted) return;
setState(() {
_loadingPath = false;
print(_paths!.last.name);
_fileName = _paths != null ?
_paths!.map((e) => e.name).toString() : '...';
});
}
void _openDocumentFileExplorer() async {
setState(() => _loadingPath = true);
try{
var files = (await FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
))
?.files;
_paths = _paths!..addAll(files!.map((e) => e));
_loadingPath = false;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
/*
try {
_paths = (await FilePicker.platform.pickFiles(
type: FileType.custom,
allowMultiple: _multiPick,
allowedExtensions: ['pdf','docx'],
))
?.files;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
if (!mounted) return;
setState(() {
_loadingPath = false;
print(_paths!.last.name);
_fileName = _paths != null ?
_paths!.map((e) => e.name).toString() : '...';
});
*/
}
void _clearCachedFiles() {
FilePicker.platform.clearTemporaryFiles().then((result) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: result! ? Colors.green : Colors.red,
content: Text((result
? 'Temporary files removed with success.'
: 'Failed to clean temporary files')),
),
);
});
}
// Select and image from the gallery or take a picture with the camera
// Then upload to Firebase Storage
/*
Future<void> _upload() async {
try {
final String fileName = _fileName;
File imageFile = File(_paths.toString());
try {
// Uploading the selected image with some custom meta data
await storage.ref(fileName).putFile(
imageFile,
);
// Refresh the UI
setState(() {});
} on FirebaseException catch (error) {
print(error);
}
} catch (err) {
print(err);
}
}
*/
// Delete the selected image
// This function is called when a trash icon is pressed
void _delete(int index) {
if(_paths!=null || _paths!.length> 1) {
_paths!.removeAt(index);
setState(() {});
print ('2:' +_paths!.length.toString());
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('File Picker example app'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
child:Card(
child:
Container(
// color: Colors.red,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
//Attachement
FlatButton(
onPressed: () { },
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.attach_file),
Text('Attachement'),
],
)
),
onTap: () {
},
),
),
//Photo
FlatButton(
onPressed: () { },
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.add_a_photo_rounded),
Text('Photo'),
],
)
),
onTap: () {_openPictureFileExplorer(); },
),
),
],
),
)),
),
Builder(
builder: (BuildContext context) => _loadingPath ?
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child:const CircularProgressIndicator(),
)
: _paths != null && _paths!.isNotEmpty
? Container(
padding: const EdgeInsets.only(bottom: 30.0),
height:
MediaQuery.of(context).size.height * 0.50,
child: Scrollbar(
child: ListView.separated(
itemCount:
_paths != null && _paths!.isNotEmpty
? _paths!.length
: 1,
itemBuilder:
(BuildContext context, int index) {
final bool isMultiPath =
_paths != null && _paths!.isNotEmpty;
final String name =
(isMultiPath
? _paths!
.map((e) => e.name)
.toList()[index]
: _fileName ?? '...');
final path = _paths!
.map((e) => e.path)
.toList()[index]
.toString();
return Container(
height: 114,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: ClipPath(
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 113,width: 113,
child: Image.file(File(path),
fit: BoxFit.fill,
width: double.infinity,),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(name,
style: TextStyle(fontWeight: FontWeight.bold),),
),
),
Padding(
padding: const EdgeInsets.only(right:25.0),
child: IconButton(onPressed: (){
//delete a record and the card displaying this record
_delete(index);
},
icon:Icon (Icons.delete, color: Colors.red,),),
)
],
),
),
//subtitle: Text(path),
),
);
},
separatorBuilder:
(BuildContext context, int index) =>
const SizedBox(),)),)
:const SizedBox(child:Text('No documents')),
),
],
),
),
)),
),
);
}
}
这里的问题是 paths
变量由 PlatformFile 列表组成,而您正试图删除该列表中不存在的字符串值。
如果在 _delete() 方法中打印 paths
的值,您可以看到这一点。它应该显示 [Instance of 'PlatformFile', Instance of 'PlatformFile']
.
简而言之,您尝试做的事情可以这样形象化
[PlatformFile(), PlatformFile()].remove("some/path/string/value")
假设列表未排序,可以有一个简单的修复方法,您可以发送索引作为 onTap
的参考。
看起来像这样
void _delete(int ref) {
// remove the element at the passed index
_paths!.removeAt(ref);
setState(() {});
}
... some code...
itemBuilder: (BuildContext context, int index) {
... some code...
IconButton(
onPressed: () {
_delete(index);
setState(() {});
},
icon: Icon(
Icons.delete,
color: Colors.red,
),
... some code...
);
}
或者,如果您不能确定路径列表中元素的位置,这将是最好的方法。
void _delete(String ref) {
var _platformFileObject = _paths!.where((element) => element.path == ref).first;
_paths!.remove(_platformFileObject);
setState(() {});
}
编辑以回答第二个问题;
在您的 _openFileExplorer()
方法中,您正在重新分配新的文件对象,而不是将它们添加到 _paths
列表中。解决方案是将新文件对象添加到列表中。
FilePickerResult? filePickerResult = await
FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
);
_paths?.addAll(filePickerResult!.files.map((e) => e));
编辑以回答第三个问题
您所说的错误就是因为这个[第 150-153 行]
itemCount:
_paths != null && _paths!.isNotEmpty
? _paths!.length
: 1
因此,当它进入构建器时,它正在尝试构建一个列表项,但由于列表实际上是空的,因此没有任何结果。您应该将 1 更改为 0。
为了在 _paths
列表为空时显示文本,您应该尝试这样的操作。
Scrollbar(
child: !_paths!.isEmpty
? ListView.separated(
itemCount: _paths!.length,
itemBuilder: (BuildContext context, int index) {
return Container();
},
separatorBuilder: (BuildContext context, int index) {
return Container();
},
)
: Text("Text to display when _paths is empty"),
);
此外,我建议您重构代码以提高可读性。
我正在使用 File_Picker.dart 我对我编写的功能之一有疑问。当我点击删除图标时,记录没有被删除,屏幕也没有刷新。我的意思是卡仍然显示。 另外,我正在尝试做的是能够一个一个地添加一个文件,而不删除之前选择的文件。但每次我单击调用“_openFileExplorer()”的按钮 'Open File picker' 时,先前选择的文件都会从屏幕上删除。我还没有找到如何阻止这种情况发生的方法。
如果您能帮我解决这个问题,我们将不胜感激。非常感谢。
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';
class FilePickerDemo extends StatefulWidget {
@override
_FilePickerDemoState createState() => _FilePickerDemoState();
}
class _FilePickerDemoState extends State<FilePickerDemo> {
//FirebaseStorage storage = FirebaseStorage.instance;
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
late String _fileName;
List<PlatformFile>? _paths;
bool _loadingPath = false;
bool _multiPick = true;
FileType _fileType = FileType.media;
/*
@override
void initState() {
super.initState();
Firebase.initializeApp();
}
*/
void _openPictureFileExplorer() async {
setState(() => _loadingPath = true);
/*
try{
var files = (await FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
))
?.files;
_paths = _paths!..addAll(files!.map((e) => e));
_loadingPath = false;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
*/
try {
_paths = (await FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
))
?.files;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
if (!mounted) return;
setState(() {
_loadingPath = false;
print(_paths!.last.name);
_fileName = _paths != null ?
_paths!.map((e) => e.name).toString() : '...';
});
}
void _openDocumentFileExplorer() async {
setState(() => _loadingPath = true);
try{
var files = (await FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
))
?.files;
_paths = _paths!..addAll(files!.map((e) => e));
_loadingPath = false;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
/*
try {
_paths = (await FilePicker.platform.pickFiles(
type: FileType.custom,
allowMultiple: _multiPick,
allowedExtensions: ['pdf','docx'],
))
?.files;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
if (!mounted) return;
setState(() {
_loadingPath = false;
print(_paths!.last.name);
_fileName = _paths != null ?
_paths!.map((e) => e.name).toString() : '...';
});
*/
}
void _clearCachedFiles() {
FilePicker.platform.clearTemporaryFiles().then((result) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: result! ? Colors.green : Colors.red,
content: Text((result
? 'Temporary files removed with success.'
: 'Failed to clean temporary files')),
),
);
});
}
// Select and image from the gallery or take a picture with the camera
// Then upload to Firebase Storage
/*
Future<void> _upload() async {
try {
final String fileName = _fileName;
File imageFile = File(_paths.toString());
try {
// Uploading the selected image with some custom meta data
await storage.ref(fileName).putFile(
imageFile,
);
// Refresh the UI
setState(() {});
} on FirebaseException catch (error) {
print(error);
}
} catch (err) {
print(err);
}
}
*/
// Delete the selected image
// This function is called when a trash icon is pressed
void _delete(int index) {
if(_paths!=null || _paths!.length> 1) {
_paths!.removeAt(index);
setState(() {});
print ('2:' +_paths!.length.toString());
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('File Picker example app'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
child:Card(
child:
Container(
// color: Colors.red,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
//Attachement
FlatButton(
onPressed: () { },
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.attach_file),
Text('Attachement'),
],
)
),
onTap: () {
},
),
),
//Photo
FlatButton(
onPressed: () { },
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.add_a_photo_rounded),
Text('Photo'),
],
)
),
onTap: () {_openPictureFileExplorer(); },
),
),
],
),
)),
),
Builder(
builder: (BuildContext context) => _loadingPath ?
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child:const CircularProgressIndicator(),
)
: _paths != null && _paths!.isNotEmpty
? Container(
padding: const EdgeInsets.only(bottom: 30.0),
height:
MediaQuery.of(context).size.height * 0.50,
child: Scrollbar(
child: ListView.separated(
itemCount:
_paths != null && _paths!.isNotEmpty
? _paths!.length
: 1,
itemBuilder:
(BuildContext context, int index) {
final bool isMultiPath =
_paths != null && _paths!.isNotEmpty;
final String name =
(isMultiPath
? _paths!
.map((e) => e.name)
.toList()[index]
: _fileName ?? '...');
final path = _paths!
.map((e) => e.path)
.toList()[index]
.toString();
return Container(
height: 114,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: ClipPath(
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 113,width: 113,
child: Image.file(File(path),
fit: BoxFit.fill,
width: double.infinity,),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(name,
style: TextStyle(fontWeight: FontWeight.bold),),
),
),
Padding(
padding: const EdgeInsets.only(right:25.0),
child: IconButton(onPressed: (){
//delete a record and the card displaying this record
_delete(index);
},
icon:Icon (Icons.delete, color: Colors.red,),),
)
],
),
),
//subtitle: Text(path),
),
);
},
separatorBuilder:
(BuildContext context, int index) =>
const SizedBox(),)),)
:const SizedBox(child:Text('No documents')),
),
],
),
),
)),
),
);
}
}
这里的问题是 paths
变量由 PlatformFile 列表组成,而您正试图删除该列表中不存在的字符串值。
如果在 _delete() 方法中打印 paths
的值,您可以看到这一点。它应该显示 [Instance of 'PlatformFile', Instance of 'PlatformFile']
.
简而言之,您尝试做的事情可以这样形象化
[PlatformFile(), PlatformFile()].remove("some/path/string/value")
假设列表未排序,可以有一个简单的修复方法,您可以发送索引作为 onTap
的参考。
看起来像这样
void _delete(int ref) {
// remove the element at the passed index
_paths!.removeAt(ref);
setState(() {});
}
... some code...
itemBuilder: (BuildContext context, int index) {
... some code...
IconButton(
onPressed: () {
_delete(index);
setState(() {});
},
icon: Icon(
Icons.delete,
color: Colors.red,
),
... some code...
);
}
或者,如果您不能确定路径列表中元素的位置,这将是最好的方法。
void _delete(String ref) {
var _platformFileObject = _paths!.where((element) => element.path == ref).first;
_paths!.remove(_platformFileObject);
setState(() {});
}
编辑以回答第二个问题;
在您的 _openFileExplorer()
方法中,您正在重新分配新的文件对象,而不是将它们添加到 _paths
列表中。解决方案是将新文件对象添加到列表中。
FilePickerResult? filePickerResult = await
FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
);
_paths?.addAll(filePickerResult!.files.map((e) => e));
编辑以回答第三个问题
您所说的错误就是因为这个[第 150-153 行]
itemCount:
_paths != null && _paths!.isNotEmpty
? _paths!.length
: 1
因此,当它进入构建器时,它正在尝试构建一个列表项,但由于列表实际上是空的,因此没有任何结果。您应该将 1 更改为 0。
为了在 _paths
列表为空时显示文本,您应该尝试这样的操作。
Scrollbar(
child: !_paths!.isEmpty
? ListView.separated(
itemCount: _paths!.length,
itemBuilder: (BuildContext context, int index) {
return Container();
},
separatorBuilder: (BuildContext context, int index) {
return Container();
},
)
: Text("Text to display when _paths is empty"),
);
此外,我建议您重构代码以提高可读性。