简体   繁体   English

如何遍历 map 列表并在 flutter 列表视图中显示文本小部件?

[英]How to iterate through list of map and display Text widget in flutter listview?

I'm very new to flutter I'm trying to display listview through for loop from the list of contents but I was able to print one list row which is one iteration as return fires only once.我对 flutter 非常陌生,我试图通过 for 循环从内容列表中显示列表视图,但我能够打印一个列表行,这是一次迭代,因为返回只触发一次。 How to iterate through the complete list and display all listview elements?如何遍历完整列表并显示所有列表视图元素? below is the list of map content以下是 map 内容列表

 List<Map<String, String>> users = [
    {"name": "Staff 1", "status": "Online"},
    {"name": "Staff 2", "status": "Online"},
    {"name": "Staff 3", "status": "Offline"},
    {"name": "Vehicle 1", "status": "Available"},
    {"name": "Vehicle 2", "status": "Unavailable"},
    {"name": "Team 1", "status": "Active"},
    {"name": "Team 2", "status": "Not Active"},
  ];

below is the code for the listview widget which I'm trying to display下面是我要显示的 listview 小部件的代码

  Widget ListViewBuilder() {
        for (var i = 0; i < users.length; i++) {
          print(i);
          return Expanded(
            child: ListView(
              children: <Widget>[
                GestureDetector(
                  onTap: () {
                    Navigator.pushNamed(
                      context,
                      '/chatscreen',
                    );
                  },
                  child: ListTile(
                      leading: CircleAvatar(
                          radius: 20,
                          backgroundImage: AssetImage("assets/profileavatar.png")),
                      title: Text(users[i]['name']),
                      subtitle: Text("User -ID"),
                      trailing: Row(
                          mainAxisAlignment:
                              MainAxisAlignment.spaceBetween, // added line
                          mainAxisSize: MainAxisSize.min,
                          children: <Widget>[
                            Text(
                              users[i]['status'],
                              style: TextStyle(
                                color: Colors.green,
                                fontSize: 20,
                          ),
                 ),                          
              ],
            ),
          );
        }
      }

this will display only first element in the list, how can I achieve to display all listview elements present in list users?这将只显示列表中的第一个元素,我怎样才能显示列表用户中存在的所有 listview 元素? any advice will be helpful任何建议都会有所帮助

The problem here is - you are returning the result in the first loop.这里的问题是 - 您在第一个循环中返回结果。 This is why you only get first element in the list.这就是为什么您只能获得列表中的第一个元素。

You need to iterate through your map within the ListView widget.您需要在 ListView 小部件中遍历您的 map。

List<Map<String, String>> users = [
    {"name": "Staff 1", "status": "Online"},
    {"name": "Staff 2", "status": "Online"},
    {"name": "Staff 3", "status": "Offline"},
    {"name": "Vehicle 1", "status": "Available"},
    {"name": "Vehicle 2", "status": "Unavailable"},
    {"name": "Team 1", "status": "Active"},
    {"name": "Team 2", "status": "Not Active"},
  ];

Widget ListViewBuilder(BuildContext context) {
      return Expanded(
        child: ListView(
          children: <Widget>[
            ...users.map( (u) => 
            <Widget> [GestureDetector(
              onTap: () {
                Navigator.pushNamed(
                  context,
                  '/chatscreen',
                );
              },
              child: ListTile(
                  leading: CircleAvatar(
                      radius: 20,
                      backgroundImage: AssetImage("assets/profileavatar.png")),
                  title: Text(u['name']),
                  subtitle: Text("User -ID"),
                  trailing: Row(
                      mainAxisAlignment:
                          MainAxisAlignment.spaceBetween, // added line
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        Text(
                          u['status'],
                          style: TextStyle(
                            color: Colors.green,
                            fontSize: 20,
                          ),
                        ),
                        SizedBox(
                          width: 20,
                        ),
                        InkWell(
                          onTap: () {
                            Navigator.pushNamed(
                              context,
                              '/viewlocation',
                            );
                          },
                          child: Icon(
                            Icons.add_location,
                            color: Colors.green,
                            size: 40,
                          ),
                        ),
                        SizedBox(
                          width: 20,
                        ),
                        Container(
                          decoration: BoxDecoration(
                              color: Colors.green,
                              border: Border.all(
                                color: Colors.green,
                              ),
                              borderRadius:
                                  BorderRadius.all(Radius.circular(20))),
                          child: InkWell(
                            onTap: () async {
                              const number =
                                  '08592119XXXX'; //set the number here
                              bool res =
                                  await FlutterPhoneDirectCaller.callNumber(
                                      number);
                            },
                            child: Icon(
                              Icons.call,
                              color: Colors.white,
                              size: 40,
                            ),
                          ),
                        )
                      ])),
            ),
            Divider(
              color: Colors.black,
              endIndent: 10,
              indent: 10,
            )
            ]).expand((element) => element).toList()
            ,
          ],
        ),
      );
 
  }

Few things are happening here:这里发生的事情很少:

  • users.map() will run supplied function on each element of your list. users.map() 将在列表的每个元素上运行提供的 function。

  • since you want to create mini-list of two elements - GestureDetector and Divider, the function will return List of Widgets由于您要创建两个元素的迷你列表 - GestureDetector 和 Divider,因此 function 将返回小部件列表

  • result of your map funciton will be [[GestureDetector, Divider], [GestureDetector, Divider],...].您的 map 功能的结果将是 [[GestureDetector, Divider], [GestureDetector, Divider],...]。 This is why we run expand to flatten it ( https://api.dart.dev/stable/2.10.5/dart-core/Iterable/expand.html )这就是为什么我们运行 expand 来压平它( https://api.dart.dev/stable/2.10.5/dart-core/Iterable/expand.ZFC35FDC70D5FC69D2369883A8ZE2

  • finally, spread operator (...) is used (...users.map( (u) =>) to unload elements into encompassing list. so this:最后,使用扩展运算符 (...) (...users.map( (u) =>) 将元素卸载到包含列表中。所以这是:

child: ListView(
          children: <Widget>[
      [GestureDetector, Divider, GestureDetector, Divider]]

becomes变成

child: ListView(
          children: <Widget>[
      GestureDetector, Divider, GestureDetector, Divider]

EDIT: I spaced on that divider you had in there and I agree with @Sam Chan suggesting ListView.separated instead of my earlier recommendation of ListView.builder .编辑:我在你那里的那个分隔符上隔开,我同意@Sam Chan 建议ListView.separated而不是我之前推荐的ListView.builder

For starters, it'll be way cleaner to extract your ListTile to its own widget and pass in a couple strings.对于初学者来说,将ListTile提取到它自己的小部件并传入几个字符串会更干净。 Otherwise it gets messy really fast.否则它会很快变得混乱。 Here's an example of that.这是一个例子。

class CustomListTile extends StatelessWidget {
  final String name, status;

  const CustomListTile({Key key, this.name, this.status}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        Navigator.pushNamed(
          context,
          '/chatscreen',
        );
      },
      child: ListTile(
        leading: CircleAvatar(
            radius: 20,
            backgroundImage: AssetImage("assets/profileavatar.png")),
        title: Text(name),
        subtitle: Text("User -ID"),
        trailing: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween, // added line
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Text(
              status,
              style: TextStyle(
                color: Colors.green,
                fontSize: 20,
              ),
            ),
            SizedBox(
              width: 20,
            ),
            InkWell(
              onTap: () {
                Navigator.pushNamed(
                  context,
                  '/viewlocation',
                );
              },
              child: Icon(
                Icons.add_location,
                color: Colors.green,
                size: 40,
              ),
            ),
            SizedBox(
              width: 20,
            ),
            Container(
              decoration: BoxDecoration(
                  color: Colors.green,
                  border: Border.all(
                    color: Colors.green,
                  ),
                  borderRadius: BorderRadius.all(Radius.circular(20))),
              child: InkWell(
                onTap: () async {
                  const number = '08592119XXXX'; //set the number here
                  // bool res = await FlutterPhoneDirectCaller.callNumber(number);
                },
                child: Icon(
                  Icons.call,
                  color: Colors.white,
                  size: 40,
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

Here's an example of a full page displaying your list of maps.这是显示您的地图列表的完整页面的示例。

class DemoPage extends StatelessWidget {
  DemoPage({
    Key key,
  }) : super(key: key);

  final List<Map<String, String>> users = [
    {"name": "Staff 1", "status": "Online"},
    {"name": "Staff 2", "status": "Online"},
    {"name": "Staff 3", "status": "Offline"},
    {"name": "Vehicle 1", "status": "Available"},
    {"name": "Vehicle 2", "status": "Unavailable"},
    {"name": "Team 1", "status": "Active"},
    {"name": "Team 2", "status": "Not Active"},
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [   
          Expanded(
            child: ListView.separated(
              separatorBuilder: (BuildContext context, int index) => Divider(
                color: Colors.black,
                endIndent: 10,
                indent: 10,
              ),
              itemCount: users.length,
              itemBuilder: (context, index) {
                // parsing the maps in the list before passing them into the extracted widget
                // the itemBuilder iterates through the list
                final name = users[index]['name'];
                final status = users[index]['status'];
                return CustomListTile(name: name, status: status);
              },
            ),
          ),
        ],
      ),
    );
  }
}

在此处输入图像描述

The problem is that you build the ListView in every loop.问题是您在每个循环中都构建ListView You can use loop to build a ListTile list and pass to ListView您可以使用循环来构建ListTile列表并传递给ListView

BUT I suggest you to use ListView.separated , it is easier.但我建议你使用ListView.separated ,它更容易。 like喜欢

  Widget listViewBuilder() {
    return Expanded(
        child: ListView.separated(
            itemCount: users.length,
            itemBuilder: (context, i) {
              return GestureDetector(
                onTap: () {
                  Navigator.pushNamed(
                    context,
                    '/chatscreen',
                  );
                },
                child: ListTile(
                    leading: CircleAvatar(
                        radius: 20,
                        backgroundImage:
                            AssetImage("assets/profileavatar.png")),
                    title: Text(users[i]['name']),
                    subtitle: Text("User -ID"),
                    trailing: Row(
                        mainAxisAlignment:
                            MainAxisAlignment.spaceBetween, // added line
                        mainAxisSize: MainAxisSize.min,
                        children: <Widget>[
                          Text(
                            users[i]['status'],
                            style: TextStyle(
                              color: Colors.green,
                              fontSize: 20,
                            ),
                          ),
                          SizedBox(
                            width: 20,
                          ),
                          InkWell(
                            onTap: () {
                              Navigator.pushNamed(
                                context,
                                '/viewlocation',
                              );
                            },
                            child: Icon(
                              Icons.add_location,
                              color: Colors.green,
                              size: 40,
                            ),
                          ),
                          SizedBox(
                            width: 20,
                          ),
                          Container(
                            decoration: BoxDecoration(
                                color: Colors.green,
                                border: Border.all(
                                  color: Colors.green,
                                ),
                                borderRadius:
                                    BorderRadius.all(Radius.circular(20))),
                            child: InkWell(
                              onTap: () async {
                                const number =
                                    '08592119XXXX'; //set the number here
                                bool res =
                                    await FlutterPhoneDirectCaller.callNumber(
                                        number);
                              },
                              child: Icon(
                                Icons.call,
                                color: Colors.white,
                                size: 40,
                              ),
                            ),
                          )
                        ])),
              );
            },
            separatorBuilder: (BuildContext context, int index) {
              return Divider(
                color: Colors.black,
                endIndent: 10,
                indent: 10,
              );
            }));
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM