Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Flutter 颤振:将列表另存为收藏夹_Flutter_Dart_Flutter Listview - Fatal编程技术网

Flutter 颤振:将列表另存为收藏夹

Flutter 颤振:将列表另存为收藏夹,flutter,dart,flutter-listview,Flutter,Dart,Flutter Listview,我有一个JSON数据文件,看起来像这样,因为你可以看到“景点”是每个城市下的一个列表: [ { "city": "text text text", "attractions": [ "text text ", "text text" ], }, { "c

我有一个JSON数据文件,看起来像这样,因为你可以看到“景点”是每个城市下的一个列表:

[
    {
        "city": "text text text",
        "attractions": [
            "text text ",
            "text text"
        ],
    },
    {
        "city": "text text text",
        "attractions": [
            "text text",
            "text text",
        ],
    },
]
下面的代码基本上是一个listview构建器,它从上面的JSON获取数据。现在,当单击该城市时,它将导航到下一页,其中显示该城市的景点列表。从代码中可以看到,有一个选项可将另一页中的城市另存为收藏夹,该选项可显示在另一个已保存收藏夹列表中:

class Index extends StatefulWidget {
  @override
  _IndexState createState() => _IndexState();
}
List data;
List<Cities> citylist = List();
List<Cities> citysavedlist = List();
int index;
class _IndexState extends State<Index> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: listView(),
    );
  }
  Future<String> fetchData() async {
    String data =
        await DefaultAssetBundle.of(context).loadString("assets/data.json");
    final jsonResult = json.decode(data);
    this.setState(() {
      jsonResult
          .forEach((element) => citylist.add(new Cities.fromJson(element)));
    });
    return "Success!";
  }

  @override
  void initState() {
    super.initState();
    fetchData();
  }

  listView() {
    return ListView.builder(
      itemCount: citylist == null ? 0 : citylist.length,
      itemBuilder: (context, index) {
        return Column(
          children: <Widget>[_buildRow(index, citylist)],
        );
      },
    );
  }

  Widget _buildRow(index, citylist) {
    final bool alreadySaved = citysavedlist.contains(citylist[index]);
    return Padding(
      padding: const EdgeInsets.only(top: 5.0, left: 5.0, right: 5.0),
      child: Card(
        child: ListTile(
            title:
                Text(citylist[index].title, style: TextStyle(fontSize: 22.0)),
            trailing: IconButton(
              icon: Icon(
                alreadySaved ? Icons.star : Icons.star_border,
                color: alreadySaved ? Colors.blue : Colors.blue,
              ),
              onPressed: () {
                setState(() {
                  if (alreadySaved) {
                    citysavedlist.remove(citylist[index]);
                  } else {
                    citysavedlist.add(citylist[index]);
                  }
                });
              },
            ), //subtitle: Text(subtitle),
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => Detail(citylist[index])));
            }),
      ),
    );
  }


void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
          final Iterable<ListTile> tiles = citysavedlist.map(
            (Cities pair) {
              return ListTile(
                  title: Text(
                    pair.city,
                  ),
                  onTap: () {
                    Navigator.push(context,
                        MaterialPageRoute(builder: (context) => Detail(pair)));
                  });
            },
          );

          final List<Widget> divided = ListTile.divideTiles(
            context: context,
            tiles: tiles,
          ).toList();
          return Scaffold(
            appBar: AppBar(
              title: const Text('Saved Suggestions'),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }
}
类索引扩展StatefulWidget{
@凌驾
_IndexState createState()=>U IndexState();
}
列出数据;
List citylist=List();
List citysavedlist=List();
整数指数;
类_IndexState扩展状态{
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(),
正文:listView(),
);
}
Future fetchData()异步{
字符串数据=
等待DefaultAssetBundle.of(context.loadString(“assets/data.json”);
最终jsonResult=json.decode(数据);
此.setState(){
jsonResult
.forEach((元素)=>citylist.add(new Cities.fromJson(元素));
});
返回“成功!”;
}
@凌驾
void initState(){
super.initState();
fetchData();
}
listView(){
返回ListView.builder(
itemCount:citylist==null?0:citylist.length,
itemBuilder:(上下文,索引){
返回列(
儿童:[[U buildRow(索引,城市列表)],
);
},
);
}
Widget\u buildRow(索引,城市列表){
final bool alreadySaved=citysavedlist.contains(citylist[index]);
返回填充(
填充:仅限常量边集(顶部:5.0,左侧:5.0,右侧:5.0),
孩子:卡片(
孩子:ListTile(
标题:
文本(城市列表[index]。标题,样式:TextStyle(fontSize:22.0)),
尾随:图标按钮(
图标:图标(
已保存?Icons.star:Icons.star\u边框,
颜色:已保存?颜色。蓝色:颜色。蓝色,
),
已按下:(){
设置状态(){
如果(已保存){
citysavedlist.remove(citylist[index]);
}否则{
citysavedlist.add(citylist[index]);
}
});
},
),//副标题:文本(副标题),
onTap:(){
导航器。推(
上下文
材料路线(
生成器:(上下文)=>详细信息(城市列表[索引]);
}),
),
);
}
作废(){
导航器.of(上下文).push(
材料路线(
生成器:(BuildContext上下文){
最终Iterable tiles=citysavedlist.map(
(城市对){
返回列表块(
标题:正文(
巴黎,
),
onTap:(){
Navigator.push(上下文,
MaterialPage路线(生成器:(上下文)=>细节(对));
});
},
);
最终列表分割=ListTile.divideTiles(
上下文:上下文,
瓷砖:瓷砖,
).toList();
返回脚手架(
appBar:appBar(
标题:常量文本(“保存的建议”),
),
正文:列表视图(子项:已分割),
);
},
),
);
}
}
这是模型类:

List<Cities> citiesFromJson(String str) =>
    List<Cities>.from(json.decode(str).map((x) => Cities.fromJson(x)));
String citiesToJson(List<Cities> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Cities {
  Cities({
    this.city,
    this.attractions,
  });

  String city;
  List<String> attractions;

  factory Cities.fromJson(Map<String, dynamic> json) => Cities(
        city: json["city"],
        attractions: List<String>.from(json["attractions"].map((x) => x)),
      );

  Map<String, dynamic> toJson() => {
        "city": city,
        "attractions": List<dynamic>.from(attractions.map((x) => x)),
      };
}
List citiesFromJson(字符串str)=>
List.from(json.decode(str.map)(x)=>Cities.fromJson(x));
字符串citiesToJson(列表数据)=>
encode(List.from(data.map((x)=>x.toJson());
阶级城市{
城市({
这个城市,
这个,景点,,
});
字符串城市;
列出景点;
工厂城市。fromJson(映射json)=>城市(
城市:json[“城市”],
景点:List.from(json[“景点”].map((x)=>x)),
);
映射到JSON()=>{
“城市”:城市,
“景点”:列表从(景点地图((x)=>x)),
};
}
下面的代码是我需要你帮助的地方,它是详细信息页面,当有人点击一个城市时,这个页面以列表的形式显示每个城市的景点。在这个页面中,我希望能够将景点保存为收藏夹,以便在另一个页面中显示

class Detail extends StatefulWidget {
  final Cities cities;
  Detail(this.cities);
  @override
  _DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.cities.city),
      ),
      body: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                widget.cities.city,
                style: TextStyle(fontSize: 20),
              ),
            ),
            Expanded(
              child: ListView.builder(
                itemCount: widget.cities.attractions.length,
                itemBuilder: (BuildContext context, int index) {
                  return Card(
                      child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text(widget.cities.attractions[index]),
                  ));
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}
类详细信息扩展StatefulWidget{
最终城市;
详细信息(本部分为城市);
@凌驾
_DetailState createState()=>\u DetailState();
}
类_DetailState扩展了状态{
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:文本(widget.cities.city),
),
主体:容器(
子:列(
crossAxisAlignment:crossAxisAlignment.start,
儿童:[
填充物(
填充:常数边集全部(8.0),
子:文本(
城市,城市,
样式:TextStyle(字体大小:20),
),
),
扩大(
子项:ListView.builder(
itemCount:widget.cities.attractions.length,
itemBuilder:(构建上下文,int索引){
回程卡(
孩子:填充(
填充:常数边集全部(8.0),
子:文本(widget.cities.attractions[index]),
));
},
),
),
],
),
),
);
}
}
我需要您的帮助,请添加此功能“将景点另存为收藏夹”。我需要将所有保存的景点显示在一个的“保存的景点页面”中,无论它属于哪个城市


有人能帮忙吗请看一下我做的例子。 以下是我添加的json,我刚刚更改了数据,以便于您理解

[
   {
       "city": "Canada",
       "attractions": [
           "Niagara Falls: An Elegant View",
           "Whistler: Your Perfect Ski Resort"
       ]
   },
   {
       "city": "Germany",
       "attractions": [
           "Berlin",
           "Munich"
       ]
   }
]

您提供的json中的模型类:

// To parse this JSON data, do
//
//     final cities = citiesFromJson(jsonString);

import 'dart:convert';

List<Cities> citiesFromJson(String str) => List<Cities>.from(json.decode(str).map((x) => Cities.fromJson(x)));

String citiesToJson(List<Cities> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Cities {
    Cities({
        this.city,
        this.attractions,
    });

    String city;
    List<String> attractions;

    factory Cities.fromJson(Map<String, dynamic> json) => Cities(
        city: json["city"],
        attractions: List<String>.from(json["attractions"].map((x) => x)),
    );

    Map<String, dynamic> toJson() => {
        "city": city,
        "attractions": List<dynamic>.from(attractions.map((x) => x)),
    };
}

//要解析此JSON数据,请执行以下操作
//
//fi
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Index(),
    );
  }
}

class Index extends StatefulWidget {
  @override
  _IndexState createState() => _IndexState();
}

List data;
List<Cities> citylist = List();
List<Cities> citysavedlist = List();
int index;

class _IndexState extends State<Index> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: listView(),
    );
  }

  Future<String> fetchData() async {
    String data =
        await DefaultAssetBundle.of(context).loadString("json/parse.json");
    final jsonResult = json.decode(data);
    this.setState(() {
      jsonResult
          .forEach((element) => citylist.add(new Cities.fromJson(element)));
    });
    return "Success!";
  }

  @override
  void initState() {
    super.initState();
    fetchData();
  }

  listView() {
    return ListView.builder(
      itemCount: citylist == null ? 0 : citylist.length,
      itemBuilder: (context, index) {
        return Column(
          children: <Widget>[_buildRow(index, citylist)],
        );
      },
    );
  }

  Widget _buildRow(index, citylist) {
    final bool alreadySaved = citysavedlist.contains(citylist[index]);
    return Padding(
      padding: const EdgeInsets.only(top: 5.0, left: 5.0, right: 5.0),
      child: Card(
        child: ListTile(
            title: Text(citylist[index].city, style: TextStyle(fontSize: 22.0)),
            trailing: IconButton(
              icon: Icon(
                alreadySaved ? Icons.star : Icons.star_border,
                color: alreadySaved ? Colors.blue : Colors.blue,
              ),
              onPressed: () {
                setState(() {
                  if (alreadySaved) {
                    citysavedlist.remove(citylist[index]);
                  } else {
                    citysavedlist.add(citylist[index]);
                  }
                });
              },
            ), //subtitle: Text(subtitle),
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => Detail(citylist[index])));
            }),
      ),
    );
  }

  void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
          final Iterable<ListTile> tiles = citysavedlist.map(
            (Cities pair) {
              return ListTile(
                  title: Text(
                    pair.city,
                  ),
                  onTap: () {
                    Navigator.push(context,
                        MaterialPageRoute(builder: (context) => Detail(pair)));
                  });
            },
          );

          final List<Widget> divided = ListTile.divideTiles(
            context: context,
            tiles: tiles,
          ).toList();
          return Scaffold(
            appBar: AppBar(
              title: const Text('Saved Suggestions'),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }
}

class Detail extends StatefulWidget {
  final Cities cities;
  Detail(this.cities);
  @override
  _DetailState createState() => _DetailState();
}

class _DetailState extends State<Detail> {
  List<String> attractionsSavedList = List();

  @override
  void initState() {
    super.initState();

    getData();
  }

  /* 

  This is done using the shared Prefrences where the saving structure is String

  This is where key is the unique user id, this is because if you logout with another user then this will differentiate the user and get the string based on it. 

  I have saved  a Map<String,List<String>> as String encoded it and while using it decode the string which will give you the map.
   */

  getData() async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    var stringvalue = sharedPreferences.getString("Id");
    print(stringvalue);
    if (stringvalue != null) {
      Map<String, dynamic> newMap = json.decode(stringvalue);
      print('This is the city selected : ${newMap[widget.cities.city]}');

      var newlist = newMap[widget.cities.city];
      if (newlist != null) {
        newlist.forEach((element) {
          print(element);
          attractionsSavedList.add(element);
        });
      }
    } else {
      print('No values to show');
    }

    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.cities.city),
      ),
      body: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.all(15.0),
                  child: GestureDetector(
                    onTap: () {
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => SavedAttractions()));
                    },
                    child: Text(
                      'Saved Attractions',
                      style: TextStyle(
                        fontSize: 18,
                        decoration: TextDecoration.underline,
                      ),
                    ),
                  ),
                )
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                widget.cities.city,
                style: TextStyle(fontSize: 20),
              ),
            ),
            Expanded(
              child: ListView.builder(
                itemCount: widget.cities.attractions.length,
                itemBuilder: (BuildContext context, int index) {
                  final bool attractionsExists = attractionsSavedList
                      .contains(widget.cities.attractions[index]);
                  return Card(
                      child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(widget.cities.attractions[index]),
                        IconButton(
                          onPressed: () async {
                            SharedPreferences _prefs =
                                await SharedPreferences.getInstance();

                            setState(() {
                              if (attractionsExists) {
                                attractionsSavedList
                                    .remove(widget.cities.attractions[index]);

                                String uniqueid = _prefs.getString("Id");

                                Map<String, dynamic> mapvalue =
                                    json.decode(uniqueid);

                                List list = mapvalue[widget.cities.city];

                                String stringtoRemove;

                                list.forEach((element) {
                                  if (element ==
                                      widget.cities.attractions[index]) {
                                    stringtoRemove =
                                        widget.cities.attractions[index];
                                  }
                                });

                                if (attractionsSavedList.length == 0) {
                                  list.remove(stringtoRemove);

                                  if (list.length == 0) {
                                    mapvalue.remove(stringtoRemove);
                                    _prefs.setString(
                                        "Id", json.encode(mapvalue));
                                  }
                                } else {
                                  list.remove(stringtoRemove);
                                  mapvalue.remove(stringtoRemove);
                                  
                                  mapvalue[widget.cities.city] = list;

                                  _prefs.setString("Id", json.encode(mapvalue));
                                }
                              } else {
                                print(
                                    'It does not exist in the list ${attractionsSavedList.length}');
                                attractionsSavedList
                                    .add(widget.cities.attractions[index]);

                                var uniqueId = _prefs.getString("Id");
                                if (uniqueId != null) {
                                  Map<String, dynamic> newMap =
                                      json.decode(uniqueId);
                                  if (attractionsSavedList.length > 0) {
                                    print(widget.cities.city);

                                    newMap[widget.cities.city] =
                                        attractionsSavedList;
                                    _prefs.setString("Id", json.encode(newMap));
                                  }
                                } else {
                                  if (attractionsSavedList.length > 0) {
                                    Map newMap = Map();
                                    newMap[widget.cities.city] =
                                        attractionsSavedList;
                                    _prefs.setString("Id", json.encode(newMap));
                                  }
                                }

                                /*  {
                                  widget.cities.city: attractionsSavedList
                                }; */

                                attractionsSavedList.forEach((element) {
                                  print(
                                      'This is the list after adding  $element');
                                });
                              }
                            });
                          },
                          icon: Icon(
                            attractionsExists ? Icons.star : Icons.star_border,
                            color:
                                attractionsExists ? Colors.blue : Colors.blue,
                          ),
                        )
                      ],
                    ),
                  ));
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class SavedAttractions extends StatefulWidget {
  @override
  _SavedAttractionsState createState() => _SavedAttractionsState();
}

class _SavedAttractionsState extends State<SavedAttractions> {
  List<String> attractionsList = List();
  bool _isLoading = false;

  @override
  void initState() {
    super.initState();
    getSavedAttractions();
  }

  getSavedAttractions() async {
    setState(() {
      _isLoading = true;
    });
    SharedPreferences preferences = await SharedPreferences.getInstance();

    String value = preferences.getString('Id');

    Map<String, dynamic> newMapVAlue = json.decode(value);

    newMapVAlue.forEach((key, value) {
      value.forEach((elements) {
        attractionsList.add(elements);
      });
    });

    setState(() {
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _isLoading
          ? Center(
              child: CircularProgressIndicator(),
            )
          : ListView.builder(
              itemCount: attractionsList.length,
              shrinkWrap: true,
              itemBuilder: (context, index) {
                return Card(
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text(attractionsList[index]),
                  ),
                );
              }),
    );
  }
}

List<Cities> citiesFromJson(String str) =>
    List<Cities>.from(json.decode(str).map((x) => Cities.fromJson(x)));
String citiesToJson(List<Cities> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Cities {
  Cities({
    this.city,
    this.attractions,
  });

  String city;
  List<String> attractions;

  factory Cities.fromJson(Map<String, dynamic> json) => Cities(
        city: json["city"],
        attractions: List<String>.from(json["attractions"].map((x) => x)),
      );

  Map<String, dynamic> toJson() => {
        "city": city,
        "attractions": List<dynamic>.from(attractions.map((x) => x)),
      };
}