使用 SharedPreferences 在 Flutter 中动态列表
Dynamic List in Flutter using SharedPreferences
Hello, I'm trying to make an app where I can store data inputted by the user like this one. My task is to use SharedPreferences to store the data.
I used SharedPreferences to save the data in a List
saveData() async {
List<String> itemData = [];
itemData.add(fstcontroller.text);
itemData.add(sndcontroller.text);
itemData.add(trdcontroller.text);
itemData.add(fthcontroller.text);
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setStringList("item", itemData);
}
I have 2 problems,
First Problem: whenever I click the Show Cart button, it shows this one
I don't want to display like this, I want to only display the "Item Brand", the rest will not be displayed.
Then, if I click the cell, it will display the full details of the item in the third screen.
here's the SecondScreen
class SecondScreen extends StatefulWidget {
@override
State createState() => new DynamicList();
}
class DynamicList extends State<SecondScreen> {
List<String> listItems = [];
@override
void initState() {
super.initState();
getUser();
}
getUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var itemData = prefs.getStringList("item");
setState(() {
listItems = itemData;
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: listItems.length, itemBuilder: buildList),
)
],
),
);
}
Widget buildList(BuildContext context, int index) {
return Container(
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 2,
),
borderRadius: BorderRadius.circular(5)),
child: ListTile(
title: Text(listItems[index]),
),
);
}
}
Second problem: Whenever I add multiple data, the data doesn't stack. It only replaces the data.
对于第一个问题,您的“共享首选项”保护了您添加到“项目数据”中的所有数据。您需要使用您保存的 属性 名称访问“项目数据”,仅 select 品牌。第二个问题我还没想好
我认为您需要重新考虑存储和读取数据的方式。
现在您正在存储键“item”下的四个字段的列表,因此每次存储数据时,您通过将 4 个项目字段放入列表中来删除“item”。
虽然我不确定“共享首选项”是否是最佳方式,但您可以执行以下操作:
将四个字段作为 json 序列化并将每个 json 字符串存储在列表中。
对于第二个问题,
存储它时,您应该首先检索现有列表并更新该列表,然后再将其存储回去。
var itemData = prefs.getStringList("item")
然后将新项目添加到列表中:
itemData.add(newItem)
存储更新后的列表
prefs.setStringList("item", itemData);
现在,当您检索列表时,您会检索 json 字符串
与json一起工作
import 'dart:convert';
然后使用 jsonDecode(stringJson)
从共享首选项中的 listItem 取回 kson,并在存储之前使用 jsonEncode(jsonObject)
将对象编码为字符串。
对于第一个问题,一旦你有了 json,你就可以像这样访问一个字段:
jsonItem['brand']
Ps 我在智能手机上,无法为您编写完整的代码。也许以后
编辑:现在我回到家了。
要对 json 对象进行最少的代码修改(未测试):
saveData() async {
final Map<String, String> item = Map<String, String>();
item['brand'] = fstcontroller.text;
item['size'] = sndcontroller.text);
item['quantity'] = trdcontroller.text);
item['color'] = fthcontroller.text);
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> cart = prefs.getStringList("cart");
if (cart == null) cart = [];
cart.add(jsonEncode(item));
prefs.setStringList("cart", cart);
}
然后你的第二个屏幕的代码变成(再次未测试 - 我的更改已评论):
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SecondScreen extends StatefulWidget {
@override
State createState() => new DynamicList();
}
class DynamicList extends State<SecondScreen> {
// I changed the type of your list
List<Map<String, String>> listItems = [];
@override
void initState() {
super.initState();
getUser();
}
getUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//I chaged these lines to retrieve the cart instead
final cart = prefs.getStringList("cart")!;
setState(() {
//convert the string cart List back to a list of objects:
cart.forEach((item) {
listItems.add(jsonDecode(item));
});
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: listItems.length, itemBuilder: buildList),
)
],
),
);
}
Widget buildList(BuildContext context, int index) {
return Container(
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 2,
),
borderRadius: BorderRadius.circular(5)),
child: ListTile(
// Only use the 'brand' field as title of your list
title: Text(listItems[index]['brand']!),
),
);
}
}
使用 Map 在共享偏好中存储值 Not List
.
SharedPreferences shared_User = await SharedPreferences.getInstance();
Map decode_options = jsonDecode(jsonString);
String user = jsonEncode(User.fromJson(decode_options));
shared_User.setString('user', user);
SharedPreferences shared_User = await SharedPreferences.getInstance();
Map userMap = jsonDecode(shared_User.getString('user'));
var user = User.fromJson(userMap);
class User {
final String name;
final String age;
User({this.name, this.age});
factory User.fromJson(Map<String, dynamic> parsedJson) {
return new User(
name: parsedJson['name'] ?? "",
age: parsedJson['age'] ?? "");
}
Map<String, dynamic> toJson() {
return {
"name": this.name,
"age": this.age
};
}
}
Hello, I'm trying to make an app where I can store data inputted by the user like this one. My task is to use SharedPreferences to store the data.
I used SharedPreferences to save the data in a List
saveData() async {
List<String> itemData = [];
itemData.add(fstcontroller.text);
itemData.add(sndcontroller.text);
itemData.add(trdcontroller.text);
itemData.add(fthcontroller.text);
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setStringList("item", itemData);
}
I have 2 problems, First Problem: whenever I click the Show Cart button, it shows this one
I don't want to display like this, I want to only display the "Item Brand", the rest will not be displayed. Then, if I click the cell, it will display the full details of the item in the third screen.
here's the SecondScreen
class SecondScreen extends StatefulWidget {
@override
State createState() => new DynamicList();
}
class DynamicList extends State<SecondScreen> {
List<String> listItems = [];
@override
void initState() {
super.initState();
getUser();
}
getUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var itemData = prefs.getStringList("item");
setState(() {
listItems = itemData;
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: listItems.length, itemBuilder: buildList),
)
],
),
);
}
Widget buildList(BuildContext context, int index) {
return Container(
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 2,
),
borderRadius: BorderRadius.circular(5)),
child: ListTile(
title: Text(listItems[index]),
),
);
}
}
Second problem: Whenever I add multiple data, the data doesn't stack. It only replaces the data.
对于第一个问题,您的“共享首选项”保护了您添加到“项目数据”中的所有数据。您需要使用您保存的 属性 名称访问“项目数据”,仅 select 品牌。第二个问题我还没想好
我认为您需要重新考虑存储和读取数据的方式。
现在您正在存储键“item”下的四个字段的列表,因此每次存储数据时,您通过将 4 个项目字段放入列表中来删除“item”。
虽然我不确定“共享首选项”是否是最佳方式,但您可以执行以下操作: 将四个字段作为 json 序列化并将每个 json 字符串存储在列表中。
对于第二个问题, 存储它时,您应该首先检索现有列表并更新该列表,然后再将其存储回去。
var itemData = prefs.getStringList("item")
然后将新项目添加到列表中:
itemData.add(newItem)
存储更新后的列表
prefs.setStringList("item", itemData);
现在,当您检索列表时,您会检索 json 字符串
与json一起工作
import 'dart:convert';
然后使用 jsonDecode(stringJson)
从共享首选项中的 listItem 取回 kson,并在存储之前使用 jsonEncode(jsonObject)
将对象编码为字符串。
对于第一个问题,一旦你有了 json,你就可以像这样访问一个字段:
jsonItem['brand']
Ps 我在智能手机上,无法为您编写完整的代码。也许以后
编辑:现在我回到家了。 要对 json 对象进行最少的代码修改(未测试):
saveData() async {
final Map<String, String> item = Map<String, String>();
item['brand'] = fstcontroller.text;
item['size'] = sndcontroller.text);
item['quantity'] = trdcontroller.text);
item['color'] = fthcontroller.text);
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> cart = prefs.getStringList("cart");
if (cart == null) cart = [];
cart.add(jsonEncode(item));
prefs.setStringList("cart", cart);
}
然后你的第二个屏幕的代码变成(再次未测试 - 我的更改已评论):
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SecondScreen extends StatefulWidget {
@override
State createState() => new DynamicList();
}
class DynamicList extends State<SecondScreen> {
// I changed the type of your list
List<Map<String, String>> listItems = [];
@override
void initState() {
super.initState();
getUser();
}
getUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//I chaged these lines to retrieve the cart instead
final cart = prefs.getStringList("cart")!;
setState(() {
//convert the string cart List back to a list of objects:
cart.forEach((item) {
listItems.add(jsonDecode(item));
});
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: listItems.length, itemBuilder: buildList),
)
],
),
);
}
Widget buildList(BuildContext context, int index) {
return Container(
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 2,
),
borderRadius: BorderRadius.circular(5)),
child: ListTile(
// Only use the 'brand' field as title of your list
title: Text(listItems[index]['brand']!),
),
);
}
}
使用 Map 在共享偏好中存储值 Not List
.
SharedPreferences shared_User = await SharedPreferences.getInstance();
Map decode_options = jsonDecode(jsonString);
String user = jsonEncode(User.fromJson(decode_options));
shared_User.setString('user', user);
SharedPreferences shared_User = await SharedPreferences.getInstance();
Map userMap = jsonDecode(shared_User.getString('user'));
var user = User.fromJson(userMap);
class User {
final String name;
final String age;
User({this.name, this.age});
factory User.fromJson(Map<String, dynamic> parsedJson) {
return new User(
name: parsedJson['name'] ?? "",
age: parsedJson['age'] ?? "");
}
Map<String, dynamic> toJson() {
return {
"name": this.name,
"age": this.age
};
}
}