file_picker - onPressed 不删除卡片也不刷新视图

问题描述

我正在使用 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"),);

此外,我建议您重构代码以提高可读性。