file_picker — При нажатии не удаляет карту и не обновляет представление

#flutter #filepicker

Вопрос:

Я использую 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,
        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 amp;amp; _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 amp;amp; _paths!.isNotEmpty
                                  ? _paths!.length
                                  : 1,
                              itemBuilder:
                                  (BuildContext context, int index) {
                                final bool isMultiPath =
                                    _paths != null amp;amp; _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')),
                          ),
                      ],
                ),
              ),
            )),
      ),
    );
  }
}
 

Ответ №1:

Проблема здесь в том, что paths переменная состоит из списка файлов платформы, и вы пытаетесь удалить строковое значение, которого нет в этом списке.

Вы можете увидеть это, если выведете значение paths в своем методе _delete (). Это должно быть заметно [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 amp;amp; _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"),
);
 

Кроме того, я бы рекомендовал вам провести рефакторинг кода для лучшей читабельности.

Комментарии:

1. Большое спасибо. Сейчас onTap работает нормально. Могу я, пожалуйста, спросить вас, нашли ли вы решение моего второго вопроса? Это был способ добавлять картинку одну за другой. Каждый раз, когда я нажимаю кнопку «Открыть средство выбора файлов», она удаляет все файлы из моего представления. Чтобы предоставить вам больше цветов, я хотел бы разрешить пользователям добавлять изображения по одному, а затем добавлять PDF или другой файл. В конце я должен отобразить список из нескольких изображений и файлов. Затем, нажав на кнопку, все эти файлы будут сохранены в Firebase. Я надеюсь, что это ясно. Большое спасибо

2. Я отредактировал свое решение, чтобы ответить на ваш второй вопрос @LaurentThomas

3. Надеюсь, я ответил на ваш вопрос @LaurentThomas

4. Я изменил свой код с помощью ‘var files = (ожидание FilePicker.platform.pickFiles(…». Тогда приложение ведет себя неправильно. Он отображает индикатор CircularProgressIndicator и не останавливается. Он не отображает изображения. Пожалуйста, у вас есть какие-нибудь идеи, почему?

5. Да. удаление записи работает нормально. Единственная проблема, которая у меня все еще есть, — это та, о которой я упоминал ранее. Добавляем изображение одно за другим. похоже, что приложение застряло на CircularProgressIndicator