使用 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
        };
      }
    }