在我的应用中,用户可以从图库中选择多个图像,这些图像被保存为资产列表,并将它们显示在屏幕上。这一切都发生在有状态的小部件中,我想对当前选择的图像进行编码并将编码的资产保存在列表中,然后能够对其进行解码。
我用于编码和解码名为 images
的资产列表的代码:
if (image_list.length > 0) {
for (var i = 0; i < image_list.length; i++) {
final byteData = await image_list[i].getByteData();
final tempFile =
File("${(await getTemporaryDirectory()).path}/${image_list[i].name}");
final file = await tempFile.writeAsBytes(
byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes),
);
final bytes = await file.readAsBytes();
String base64Encode(List<int> bytes) => base64.encode(bytes);
String encoded_image = base64Encode(bytes);
image_list_encoded.add(encoded_image);
}
}
return image_list_encoded;
}
Future<List<Image>> decodeImages(List<String> image_list_encoded) async {
if (new_image_list_encoded.length > 0) {
for (var i = 0; i < new_image_list_encoded.length; i++) {
final decodedBytes = base64Decode(new_image_list_encoded[i]);
var decoded_file = Image.memory(decodedBytes);
image_list_decoded.add(decoded_file);
}
}
return image_list_decoded;
}
单击检查按钮后,我尝试检查编码图像是否正确编码:
IconButton(
icon: Icon(
Icons.check,
color: Colors.white,
),
onPressed: () async {
final form = _formKey.currentState;
if (form!.validate()) {
form.save();
}
var encoded_images = await encodeImages(images);
print(savedProjectName);
print(savedProjectDescription);
print(encoded_images);
},
),
问题是,当我打印编码后的字符串时,无论选择哪张图片,打印的编码字符串都是一样的;不幸的是,我现在无法提供这个字符串,因为现在,由于 path_provider
插件不再工作,整个程序不再工作。我怀疑这是问题所在,因为一旦我安装插件并在程序中使用它,我就会收到此错误:
Error: Cannot run with sound null safety, because the following dependencies
don't support null safety:
- package:plugin_platform_interface
For solutions, see https://dart.dev/go/unsound-null-safety
Unhandled exception:
Bad state: Unsupported Null Safety mode NonNullableByDefaultCompiledMode.Invalid, in null.
#0 ProgramCompiler.emitModule (package:dev_compiler/src/kernel/compiler.dart:439:9)
#1 JavaScriptBundler.compile (package:frontend_server/src/javascript_bundle.dart:146:33)
#2 FrontendCompiler.writeJavascriptBundle (package:frontend_server/frontend_server.dart:638:47)
<asynchronous suspension>
#3 FrontendCompiler.compile (package:frontend_server/frontend_server.dart:549:9)
<asynchronous suspension>
#4 listenAndCompile.<anonymous closure> (package:frontend_server/frontend_server.dart:1119:11)
<asynchronous suspension>
the Dart compiler exited unexpectedly.
Exited (sigterm)
Failed to compile application.
但是,如果没有这个插件,我的编码函数中的函数 getTemporaryDirectory()
没有定义。您是否知道一种不同的方式来编码和解码这些资产,然后能够在以后打印编码版本?
完整代码:
ProjectDescriptionField savedDescription = ProjectDescriptionField();
ProjectNameField savedName = ProjectNameField();
AddPage savedPage = AddPage();
_AddPageState savedPageState = _AddPageState();
List<String> image_list_encoded = [];
final _formKey = GlobalKey<FormState>();
final projectNameController = TextEditingController();
final projectDescriptionController = TextEditingController();
String? savedProjectName = '';
String? savedProjectDescription = '';
List<Image> image_list_decoded = [];
List<Asset> asset_list_decoded = [];
List<String> new_image_list_encoded = image_list_encoded;
class AddPage extends StatefulWidget {
final _AddPageState _addPageState = _AddPageState();
AddPage({Key? key}) : super(key: key);
@override
_AddPageState createState() => _AddPageState();
//return _addPageState;
}
class _AddPageState extends State<AddPage> {
List<Asset> images = <Asset>[];
String _error = NOERROR;
@override
Widget build(BuildContext context) {
if (images.isEmpty)
return AppLayout(logicalHeight * 0.15);
else
return AppLayout(logicalHeight * 0.01);
}
Future<void> loadAssets() async {
List<Asset> resultList = <Asset>[];
String error = NOERROR;
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
enableCamera: true,
selectedAssets: images,
cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
materialOptions: MaterialOptions(
actionBarColor: "#abcdef",
actionBarTitle: "Example App",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
} on Exception catch (e) {
error = e.toString();
}
if (!mounted) return;
setState(() {
images = resultList;
_error = error;
});
}
List<Asset> getImages() {
return images;
}
Widget AppLayout(double distanceFromImages) {
return Scaffold(
appBar: AppBar(
leading: BackButton(color: Colors.white),
title: Text(CREATEPROJECT),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.check,
color: Colors.white,
),
onPressed: () async {
final form = _formKey.currentState;
if (form!.validate()) {
form.save();
}
var encoded_images = await encodeImages(images);
var decoded_images = decodeImages(encoded_images);
print(savedProjectName);
print(savedProjectDescription);
print(encoded_images);
},
),
],
),
body: Form(
key: _formKey,
child: Column(children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.02, 0, 0),
child: Center(
child: Container(
height: logicalHeight * 0.05,
width: logicalWidth * 0.9,
child: TextFormField(
controller: projectNameController,
decoration: InputDecoration(
hintText: PROJECTNAME, border: UnderlineInputBorder()),
maxLength: 30,
validator: (value) {
if (value!.isEmpty) {
return 'This is a required field';
}
return null;
},
onSaved: (value) => savedProjectName = value),
)),
),
Padding(
padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.01, 0, 0),
child: ElevatedButton(
child: Text(PICKIMAGES),
onPressed: loadAssets,
)),
Center(
child: Padding(
padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.01, 0, 0),
child: getWidget())),
Padding(
padding: EdgeInsets.fromLTRB(logicalWidth * 0.05,
distanceFromImages, logicalWidth * 0.05, 0),
child: Center(
child: Container(
// child: savedDescription
child: TextFormField(
controller: projectDescriptionController,
decoration: InputDecoration(
hintText: PROJECTDESCRIPTION,
border: UnderlineInputBorder()),
maxLines: 5,
minLines: 1,
maxLength: 5000,
validator: (value) {
if (value!.isEmpty) {
return 'This is a required field';
}
return null;
},
onSaved: (value) =>
savedProjectDescription = value))),
),
])),
);
}
Widget getWidget() {
if (images.length > 0) {
//Would it be better to make a list of all items in images using List.generate so that we avoid this if statement
return Container(
height: logicalHeight * 0.4,
width: logicalWidth * 0.8,
child: ImagePages());
} else {
return Padding(
padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.15, 0, 0),
child: Container(child: Text(NOPICTURESSELECTED)));
}
}
PageView ImagePages() {
final PageController controller = PageController(initialPage: 0);
List<Widget> children = [];
images.forEach((element) {
children.add(Padding(
padding: EdgeInsets.fromLTRB(
logicalWidth * 0.01, 0, logicalWidth * 0.01, 0),
child: AssetThumb(
asset: element,
width: 1000,
height: 1000,
)));
});
return PageView(
scrollDirection: Axis.horizontal,
controller: controller,
children: children,
);
}
}
Future<List<String>> encodeImages(List<Asset> image_list) async {
//use savedPage._addPageState.getImages() as image_list
if (image_list.length > 0) {
for (var i = 0; i < image_list.length; i++) {
final byteData = await image_list[i].getByteData();
final tempFile =
File("${(await getTemporaryDirectory()).path}/${image_list[i].name}");
final file = await tempFile.writeAsBytes(
byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes),
);
final bytes = await file.readAsBytes();
String base64Encode(List<int> bytes) => base64.encode(bytes);
String encoded_image = base64Encode(bytes);
image_list_encoded.add(encoded_image);
}
}
return image_list_encoded;
}
Future<List<Image>> decodeImages(List<String> image_list_encoded) async {
if (new_image_list_encoded.length > 0) {
for (var i = 0; i < new_image_list_encoded.length; i++) {
final decodedBytes = base64Decode(new_image_list_encoded[i]);
var decoded_file = Image.memory(decodedBytes);
image_list_decoded.add(decoded_file);
}
}
return image_list_decoded;
}
void saveNewProject(SavedData savedData) {
//TODO save the data to FireBase
//save data includes:
// project name
// project description
// list of assets
}
class ProjectNameField extends StatefulWidget {
ProjectNameFieldState _nameFieldState = ProjectNameFieldState();
@override
ProjectNameFieldState createState() {
return ProjectNameFieldState();
//return _nameFieldState;
}
}
class ProjectNameFieldState extends State<ProjectNameField> {
final myController = TextEditingController();
//how do you read out the information from that textfield, it may have been better to use the previous method with userInput
@override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return TextField(
controller: myController,
decoration: InputDecoration(
border: UnderlineInputBorder(),
hintText: PROJECTNAME,
),
maxLength: 30,
);
}
}
class ProjectDescriptionField extends StatefulWidget {
ProjectDescriptionFieldState _descriptionFieldState =
ProjectDescriptionFieldState();
@override
ProjectDescriptionFieldState createState() {
return _descriptionFieldState;
//return ProjectDescriptionFieldState();
}
}
class ProjectDescriptionFieldState extends State<ProjectDescriptionField> {
final myController = TextEditingController();
@override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return TextField(
controller: myController,
decoration: InputDecoration(
border: UnderlineInputBorder(),
hintText: PROJECTDESCRIPTION,
),
minLines: 1,
maxLines: 5,
maxLength: 5000,
);
}
}
class SavedData {
String saved_Project_Name = "";
String saved_Project_Description = "";
List<Asset> saved_images = [];
SavedData(String saved_Project_Name, String saved_Project_Description,
List<Asset> saved_images) {
this.saved_Project_Name = saved_Project_Name;
this.saved_Project_Description = saved_Project_Description;
this.saved_images = saved_images;
}
}