问题描述
我正在使用 File_Picker.dart 我编写的其中一个函数有问题。当我按下图标删除时,记录不会被删除,屏幕也不会刷新。我的意思是卡片仍然显示。 另外,我正在尝试做的是能够一个一个地添加文件,而无需删除先前选择的文件。但是每次我单击调用“_openFileExplorer()”的“打开文件选择器”按钮时,之前选择的文件都会从屏幕上删除。我还没有找到如何阻止这种情况发生。
如果您能帮我解决这个问题,我将不胜感激。非常感谢。
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,))
?.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,))
?.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,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,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,)
: Text("Text to display when _paths is empty"),);
此外,我建议您重构代码以提高可读性。