Flutter: данные JSON, список под списком

У меня есть файл данных JSON, который выглядит так, как вы можете видеть, электронная почта сама по себе является списком:

[
    {
        "index": 0,
        "about": "text text text",
        "email": [
            "[email protected]",
            "[email protected]",
        ],
        "name": "sample name",
        "picture": "https://kdjfksfjsdklfs.com"
    },
    {
        "index": 1,
        "about": "text text text",
        "email": [
            "[email protected]",
            "[email protected]",
        ],
        "name": "sample name ",
        "picture": "https://kdjfksfjsdklfs.com"
    },
    {
        "index": 2,
        "about": "text text text",
        "email": [
            "[email protected]",
            "[email protected]",
        ],
        "name": "sample name",
        "picture": "https://kdjfksfjsdklfs.com"
    }
]

Мой код следующий, который в основном представляет собой конструктор списка, который получает данные из приведенного выше JSON. Теперь, когда список щелкнут, он перейдет на следующую страницу, где мне нужно показать сведения об этом пользователе.

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Users'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

Future _data;

class _MyHomePageState extends State<MyHomePage> {
  Future<List<User>> _getUsers() async {
    var data =
        await DefaultAssetBundle.of(context).loadString("assets/test.json");

    var jsonData = json.decode(data);

    List<User> users = [];

    for (var u in jsonData) {
      User user =
          User(u["index"], u["about"], u["name"], u["email"], u["picture"]);

      users.add(user);
    }

    print(users.length);

    return users;
  }

  @override
  void initState() {
    super.initState();
    _data = _getUsers();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: Container(
        child: FutureBuilder(
          future: _data,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            print(snapshot.data);
            if (snapshot.data == null) {
              return Container(child: Center(child: Text("Loading...")));
            } else {
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(
                    leading: CircleAvatar(
                      backgroundImage:
                          NetworkImage(snapshot.data[index].picture),
                    ),
                    title: Text(snapshot.data[index].name),
                    // subtitle: Text(snapshot.data[index].email),
                    onTap: () {
                      Navigator.push(
                          context,
                          new MaterialPageRoute(
                              builder: (context) =>
                                  DetailPage(snapshot.data[index])));
                    },
                  );
                },
              );
            }
          },
        ),
      ),
    );
  }
}

class DetailPage extends StatelessWidget {
  final User user;

  DetailPage(this.user);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(user.name),
      ),
      body: Container(
        child: Text(user.about),
      ),
    );
  }
}

class User {
  final int index;
  final String about;
  final String name;
  final String email;
  final String picture;

  User(this.index, this.about, this.name, this.email, this.picture);
}

Я хотел создать Listview Builder на второй странице для имени и электронной почты, чтобы все электронные письма были указаны под именем.

может кто-нибудь помочь, я не могу создать второй список страниц, особенно список адресов электронной почты.


person Smart HO    schedule 29.06.2020    source источник


Ответы (2)


Просто проверьте этот пример и дайте мне знать, работает ли он для вас:

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';

import 'package:json_parsing_example/models.dart';

// To parse this JSON data, do
//
//     final user = userFromJson(jsonString);

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Users'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

Future _data;

class _MyHomePageState extends State<MyHomePage> {
  Future<List<User>> _getUsers() async {
    var data =
        await DefaultAssetBundle.of(context).loadString("json/parse.json");

    return userFromJson(data);
  }

  @override
  void initState() {
    super.initState();
    _data = _getUsers();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: Container(
        child: FutureBuilder<List<User>>(
          future: _data,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            print(snapshot.data);
            if (snapshot.data == null) {
              return Container(child: Center(child: Text("Loading...")));
            } else {
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(
                    leading: CircleAvatar(
                      backgroundImage:
                          NetworkImage(snapshot.data[index].picture),
                    ),
                    title: Text(snapshot.data[index].name),
                    // subtitle: Text(snapshot.data[index].email),
                    onTap: () {
                      Navigator.push(
                          context,
                          new MaterialPageRoute(
                              builder: (context) =>
                                  DetailPage(snapshot.data[index])));
                    },
                  );
                },
              );
            }
          },
        ),
      ),
    );
  }
}

class DetailPage extends StatefulWidget {
  final User user;

  DetailPage(this.user);

  @override
  _DetailPageState createState() => _DetailPageState();
}

class _DetailPageState extends State<DetailPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.user.name),
      ),
      body: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                widget.user.name,
                style: TextStyle(fontSize: 20),
              ),
            ),
            ListView.builder(
              shrinkWrap: true,
              itemCount: widget.user.email.length,
              itemBuilder: (BuildContext context, int index) {
                return Card(
                    child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(widget.user.email[index]),
                ));
              },
            ),
          ],
        ),
      ),
    );
  }
}


Ваш модельный класс:

// To parse this JSON data, do
//
//     final user = userFromJson(jsonString);

import 'dart:convert';

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

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

class User {
    User({
        this.index,
        this.about,
        this.email,
        this.name,
        this.picture,
    });

    int index;
    String about;
    List<String> email;
    String name;
    String picture;

    factory User.fromJson(Map<String, dynamic> json) => User(
        index: json["index"],
        about: json["about"],
        email: List<String>.from(json["email"].map((x) => x)),
        name: json["name"],
        picture: json["picture"],
    );

    Map<String, dynamic> toJson() => {
        "index": index,
        "about": about,
        "email": List<dynamic>.from(email.map((x) => x)),
        "name": name,
        "picture": picture,
    };
}

person Sagar Acharya    schedule 29.06.2020
comment
Это работает, спасибо. Но мне нужно показать имя пользователя на второй странице над электронными письмами, а не на панели приложений. Как я могу это сделать. Я имею в виду, что при запуске конструктора списка сначала отображается имя, а затем список адресов электронной почты. - person Smart HO; 30.06.2020
comment
Просто проверьте код, который я внес в изменения, используя столбец, который будет делать родитель, и имя вверху, а затем появится ваш список, и не забудьте добавить термоусадочную пленку в значение true для просмотра списка, потому что вы используете столбец, поэтому Listview будет занимать место только на основе дочернего элемента. - person Sagar Acharya; 30.06.2020
comment
Большое спасибо за поддержку. высоко ценится - person Smart HO; 30.06.2020
comment
Еще одна помощь, пожалуйста: мне нужно придумать одну переменную, чтобы объединить все электронные письма, например: var emailall = widget.user.email.join("\n\n"); , но это не работает. пожалуйста, помогите исправить это и дайте мне знать, где я его положил. Мне нужно использовать на второй странице - person Smart HO; 30.06.2020
comment
Что значит присоединиться? Можете ли вы уточнить. - person Sagar Acharya; 30.06.2020
comment
Я имею в виду объединение (или объединение) всех писем под одной переменной, одно под другим. Я хотел использовать их для функции обмена. - person Smart HO; 30.06.2020
comment
вы просто хотите показать его один под другим и при щелчке хотите сделать функциональность общего доступа. вы хотите нажать на один адрес электронной почты или полную карту?. Это немного сбивает с толку, любое графическое представление было бы лучше. - person Sagar Acharya; 30.06.2020
comment
Спасибо большое за поддержку, у меня получилось - person Smart HO; 02.07.2020

Во-первых: вы можете использовать либо

  • причал/причал_флаттер причал flutter_moor
  • OR
  • встроенное_значение встроенное_значение

    Сопоставление строки json и создание fromJson/toJson функции.

    Пример использования болота:
  • Во-первых, создайте базу данных moor (если у вас есть какие-либо вопросы, я рад ответить).
  • Во-вторых, это класс, который вы должны использовать.
import 'dart:convert';
import 'package:db/moordb/database.dart';
import 'package:json_annotation/json_annotation.dart' as json;
import 'package:moor/moor.dart';

part 'user.g.dart';

@DataClassName("User")
class Users extends Table {
  IntColumn get id => integer().nullable().autoIncrement()();

  @JsonKey("index")
  IntColumn get index => text().nullable()();

  @JsonKey("about")
  TextColumn get about => text().nullable()();

  @JsonKey("email")
  TextColumn get emails => text().map(const EmailConverter()).nullable()();

  @JsonKey("name")
  TextColumn get name => text().nullable()();

  @JsonKey("picture")
  TextColumn get picture => text().nullable()();

  @override
  Set<Column> get primaryKey => {id};
}

class EmailConverter extends TypeConverter<List<String>, String> {
  const EmailConverter ();

  @override
  List<String> mapToDart(String fromDb) {
    if (fromDb == null) {
      return null;
    }
    List _emails = List<String>();
    (jsonDecode(fromDb)).forEach((value) {
      _emails.add(value);
    });
    return _emails;
  }

  @override
  String mapToSql(List<dynamic> value) {
    if (value == null) {
      return null;
    }
    return jsonEncode(value);
  }
}

Второе:

Предпочтительно, чтобы вы отправляли объект User через:

В вашем случае вы передаете объект виджету напрямую.
В заключение, очевидно, что адрес электронной почты поля String в вашем объекте User не заполняется декодированными данными, которые содержат электронные письма в списке. (поскольку вы используете пользователя класса).

Примечание. Удалите ключевое слово new, так как оно больше не требуется в Dart 2.

person Charlie Abou Moussa    schedule 29.06.2020