Flutter文件选择插件reactive_file_selector的使用
Flutter文件选择插件reactive_file_selector的使用
reactive_file_selector
是一个用于在 Flutter 中选择文件的插件。它基于 file_selector
插件,并与 reactive_forms
集成以实现更方便的表单管理。
示例代码
下面是一个完整的示例代码,展示了如何使用 reactive_file_selector
插件来选择多个文件并验证文件数量。
import 'package:flutter/material.dart';
import 'package:reactive_file_selector/reactive_file_selector.dart';
import 'package:reactive_forms/reactive_forms.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// 构建表单
FormGroup buildForm() => fb.group({
'input': FormControl<MultiFile<String>>(
value: const MultiFile(),
validators: [
Validators.required,
FileSelectorValidators.limit(min: 5, max: 10),
]),
});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Scaffold(
appBar: AppBar(),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ReactiveFormBuilder(
form: buildForm,
builder: (context, form, child) {
return Column(
children: [
Expanded(
child: ReactiveFileSelector<String>(
formControlName: 'input',
allowMultiple: true,
distinctPickedFiles: true,
filePickerBuilder: (pickImage, files, onChange) {
final items = [
...files.files
.asMap()
.map((key, value) => MapEntry(
key,
ListTile(
onTap: () {
onChange(files.copyWith(
files:
List<String>.from(files.files)
..removeAt(key)));
},
leading: const Icon(Icons.delete),
title: FileListItem(value).build(context),
)))
.values,
...files.platformFiles
.asMap()
.map((key, value) => MapEntry(
key,
ListTile(
onTap: () {
onChange(files.copyWith(
platformFiles: List<XFile>.from(
files.platformFiles)
..removeAt(key)));
},
leading: const Icon(Icons.delete),
title: PlatformFileListItem(value)
.build(context),
),
))
.values,
];
return Column(
children: [
Expanded(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (_, i) {
return items[i];
},
),
),
ElevatedButton(
onPressed: pickImage,
child: const Text("Pick images"),
),
],
);
},
validationMessages: {
ValidationMessage.min: (error) {
if (error is! Map<String, Object?>) {
return ValidationMessage.min;
}
return "应至少有 ${error['min']} 个文件,实际有: ${error['actual']}";
},
ValidationMessage.max: (error) {
if (error is! Map<String, Object?>) {
return ValidationMessage.max;
}
return "应最多有 ${error['max']} 个文件,实际有: ${error['actual']}";
}
},
decoration: const InputDecoration(
labelText: '多文件选择器',
border: OutlineInputBorder(),
helperText: '',
),
),
),
ElevatedButton(
child: const Text('提交'),
onPressed: () {
if (form.valid) {
debugPrint(form.value.toString());
}
},
),
],
);
},
),
),
),
),
);
}
}
// 抽象类,定义列表项接口
abstract class ListItem {
Widget build(BuildContext context);
}
// 文件列表项
class FileListItem extends ListItem {
final String url;
FileListItem(this.url);
[@override](/user/override)
Widget build(context) {
return Text(url);
}
}
// 平台文件列表项
class PlatformFileListItem extends ListItem {
final XFile platformFile;
PlatformFileListItem(this.platformFile);
[@override](/user/override)
Widget build(context) {
return Text(platformFile.name);
}
}
代码解释
-
导入必要的库:
import 'package:flutter/material.dart'; import 'package:reactive_file_selector/reactive_file_selector.dart'; import 'package:reactive_forms/reactive_forms.dart';
-
构建表单:
FormGroup buildForm() => fb.group({ 'input': FormControl<MultiFile<String>>( value: const MultiFile(), validators: [ Validators.required, FileSelectorValidators.limit(min: 5, max: 10), ]), });
-
构建UI:
[@override](/user/override) Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: Scaffold( appBar: AppBar(), body: SafeArea( child: Padding( padding: const EdgeInsets.all(8.0), child: ReactiveFormBuilder( form: buildForm, builder: (context, form, child) { return Column( children: [ Expanded( child: ReactiveFileSelector<String>( formControlName: 'input', allowMultiple: true, distinctPickedFiles: true, filePickerBuilder: (pickImage, files, onChange) { // 构建文件列表 }, validationMessages: { ValidationMessage.min: (error) { // 自定义最小文件数错误信息 }, ValidationMessage.max: (error) { // 自定义最大文件数错误信息 } }, decoration: const InputDecoration( labelText: '多文件选择器', border: OutlineInputBorder(), helperText: '', ), ), ), ElevatedButton( child: const Text('提交'), onPressed: () { if (form.valid) { debugPrint(form.value.toString()); } }, ), ], ); }, ), ), ), ), ); }
-
自定义列表项:
abstract class ListItem { Widget build(BuildContext context); } class FileListItem extends ListItem { final String url; FileListItem(this.url); [@override](/user/override) Widget build(context) { return Text(url); } } class PlatformFileListItem extends ListItem { final XFile platformFile; PlatformFileListItem(this.platformFile); [@override](/user/override) Widget build(context) { return Text(platformFile.name); } }
更多关于Flutter文件选择插件reactive_file_selector的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter文件选择插件reactive_file_selector的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
reactive_file_selector
是一个 Flutter 插件,用于在 Flutter 应用程序中选择文件。它提供了一个响应式的文件选择器,可以与 Flutter 的响应式编程模型(如 Stream
或 RxDart
)无缝集成。
安装插件
首先,你需要在 pubspec.yaml
文件中添加 reactive_file_selector
插件的依赖:
dependencies:
flutter:
sdk: flutter
reactive_file_selector: ^1.0.0 # 请使用最新版本
然后,运行 flutter pub get
来安装依赖。
使用 reactive_file_selector
1. 导入插件
在你的 Dart 文件中导入 reactive_file_selector
插件:
import 'package:reactive_file_selector/reactive_file_selector.dart';
2. 创建文件选择器
你可以使用 ReactiveFileSelector
小部件来创建一个文件选择器。它通常与 StreamController
或 BehaviorSubject
一起使用,以便在文件选择时触发事件。
import 'package:flutter/material.dart';
import 'package:reactive_file_selector/reactive_file_selector.dart';
import 'package:rxdart/rxdart.dart';
class FileSelectorExample extends StatefulWidget {
@override
_FileSelectorExampleState createState() => _FileSelectorExampleState();
}
class _FileSelectorExampleState extends State<FileSelectorExample> {
final BehaviorSubject<File> _fileSubject = BehaviorSubject<File>();
@override
void dispose() {
_fileSubject.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Reactive File Selector Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ReactiveFileSelector(
onFileSelected: _fileSubject.add,
child: ElevatedButton(
onPressed: () {
// 这里不需要手动处理按钮点击事件,ReactiveFileSelector 会自动处理
},
child: Text('Select File'),
),
),
StreamBuilder<File>(
stream: _fileSubject.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text('Selected File: ${snapshot.data!.path}');
} else {
return Text('No file selected');
}
},
),
],
),
),
);
}
}
3. 处理文件选择事件
在上面的代码中,ReactiveFileSelector
小部件会在用户选择文件时触发 onFileSelected
回调,并将选中的文件添加到 _fileSubject
中。然后,StreamBuilder
会监听 _fileSubject
的变化,并在 UI 中显示选中的文件路径。
4. 自定义文件选择器
你可以通过传递不同的参数来自定义文件选择器的行为。例如,你可以指定允许选择的文件类型:
ReactiveFileSelector(
onFileSelected: _fileSubject.add,
allowedExtensions: ['.txt', '.pdf'], // 只允许选择 .txt 和 .pdf 文件
child: ElevatedButton(
onPressed: () {},
child: Text('Select File'),
),
),
5. 处理错误
你还可以通过 onError
回调来处理文件选择过程中可能发生的错误:
ReactiveFileSelector(
onFileSelected: _fileSubject.add,
onError: (error) {
print('File selection error: $error');
},
child: ElevatedButton(
onPressed: () {},
child: Text('Select File'),
),
),