ListView flutter 中如何管理不同小部件的状态?

Posted

技术标签:

【中文标题】ListView flutter 中如何管理不同小部件的状态?【英文标题】:How manage state of different widgets in ListView flutter? 【发布时间】:2022-01-17 13:42:17 【问题描述】:

我正在构建一个 Flutter 应用程序,其中使用 ListView 显示列表。它返回一个带有用户信息的 ListTile。 ListTile 包含 leadingtitlesubtitle,其中 trailing 设置为 ElevatedButton

如下所示:

我想点击“邀请按钮”并更改 ListTile 中的 colortextsubtitle

点击后应该是这个样子。

我该怎么做?这是我写的代码。但它正在改变每个列表项的状态。

class InviteFriends extends StatefulWidget 
  const InviteFriends(Key? key) : super(key: key);

  @override
  State<InviteFriends> createState() => _InviteFriendsState();


class _InviteFriendsState extends State<InviteFriends> 

  bool isSelected = false;

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

  @override
  void dispose() 
    super.dispose();
  

ListView.builder下的UI:

                       ListTile(
                            title: const Text('Haris'),
                            subtitle: const Text(
                              isSelected ? 'Invitation Sent' : 'Not Invited Yet',
                            ),
                            leading: CircleAvatar(
                              backgroundImage: NetworkImage(
                                _userProfile!.profilePhoto.toString(),
                              ),
                            ),
                            trailing: ElevatedButton(
                              style: ElevatedButton.styleFrom(
                                elevation: 0.0,
                                primary: isSelected ? Colors.orange : Colors.green,
                                side: BorderSide.none,
                                shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(10.0),
                                ),
                              ),
                              child: const Text(
                                isSelected ? 'Invited': 'Invite',
                              ),
                              onPressed: () 
                                setState(() 
                               isSelected = !isSelected;
                                );
                              ,
                            ),
                          );

我也在 ListTile 中使用 ValueKey(index) 尝试了 Keys,但它也没有工作。我该怎么办?谢谢

【问题讨论】:

【参考方案1】:
         return ListView.builder(
             itemCount: itemCount.length
              itemBuilder: (BuildContext context, int index) 
              return Friend(
              //arg if available
              );
    );

class Friend extends StatefulWidget 
  const Friend(Key? key) : super(key: key);

  @override
  _FriendState createState() => _FriendState();


class _FriendState extends State<Friend> 
  bool isSelected = false;
  @override
  Widget build(BuildContext context) 
//put ListTile detail here
    return Row(
      children: [
        FlatButton(//deprecated but other buttons work
               key: PageStorageKey('random num'),//if you are interested in keeping the state of the button while navigating
            onPressed: () 
              setState(() 
                isSelected = !isSelected;
              );
            ,
            child: Text(isSelected ? "INVITED" : "INVITE"))
      ],
    );
  

【讨论】:

【参考方案2】:

您创建一个列表,说“i”(变量)以了解每个图块的状态,并使用 false 进行初始化。点击时将状态更改为 true。

final List&lt;bool&gt; selected = List.generate(20, (i) =&gt; false);

将列表“i”传递给 listview.builder,例如:-

            itemBuilder: (BuildContext context, i) 

查看完整代码

import 'package:flutter/material.dart';

class InviteFriends extends StatefulWidget 
  const InviteFriends(Key? key) : super(key: key);

  @override
  State<InviteFriends> createState() => _InviteFriendsState();


class _InviteFriendsState extends State<InviteFriends> 
  bool isSelected = false;

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

  @override
  void dispose() 
    super.dispose();
  

  final List<bool> selected = List.generate(20, (i) => false);

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.only(top: 60),
        child: ListView.builder(
            // itemCount: i,
            itemBuilder: (BuildContext context, i) 
          return ListTile(
            title: const Text('Haris'),
            subtitle: Text(
              selected[i] ? 'Invitation Sent' : 'Not Invited Yet',
            ),
            leading: const CircleAvatar(
              backgroundImage: AssetImage('assets/profile.gif'),
            ),
            trailing: ElevatedButton(
                style: ElevatedButton.styleFrom(
                  elevation: 0.0,
                  primary: selected[i] ? Colors.orange : Colors.green,
                  side: BorderSide.none,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(10.0),
                  ),
                ),
                child: Text(
                  selected[i] ? 'Invited' : 'Invite',
                ),
                onPressed: () 
                  setState(() => selected[i] = !selected[i]);
                  // setState(() 
                  //   isSelected = !isSelected;
                  // );
                ),
          );
        ),
      ),
    );
  


谢谢

输出

【讨论】:

与使用单独的 Stateful Widget 有何不同。单独的小部件工作正常,但我不确定使用哪一个。有什么不同吗?【参考方案3】:

您需要为 listtiles 创建不同的类。执行以下操作:

 ListView.builder(
        itemCount: 3,
        shrinkWrap: true,
        itemBuilder: (ctx, i) 
          return MyListItems();
        ))

然后是 MyListItems。

    class MyListItems extends StatefulWidget 
  @override
  MyListState createState() => MyListState();


class MyListState extends State<MyListItems> 
  bool isSelected = false;

  @override
  Widget build(BuildContext context) 
    return ListTile(
      title: const Text('Haris'),
      subtitle: Text(
        isSelected ? "Invitation Sent" : 'Not Invited Yet',
      ),
      leading: const CircleAvatar(
        backgroundImage: NetworkImage(
            'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQYtfZRhbGQtq2BapB2MXJfWIO2QriO5Wx3qQ&usqp=CAU'),
      ),
     // use your image here
      trailing: ElevatedButton(
        style: ElevatedButton.styleFrom(
          elevation: 0.0,
          primary: isSelected ? Colors.orange : Colors.green,
          side: BorderSide.none,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(10.0),
          ),
        ),
        child: Text(
          isSelected ? 'Invited' : 'Invite',
        ),
        onPressed: () 
          setState(() 
            isSelected = !isSelected;
          );
        ,
      ),
    );
  

【讨论】:

【参考方案4】:

将 Tile 作为单独的 StatefulWidget 取出,以便每个都有自己的状态。 不要修改 State List.builder。 并且你对所有 Tile 使用一个 isSelected 字段,你都会参考这个条件。

请提供更多代码,我可以提供帮助。以便我了解全貌

【讨论】:

以上是关于ListView flutter 中如何管理不同小部件的状态?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter-ListView 溢出

Flutter ListView 与不同的小部件和列表项

如何在 Flutter 的 ListView 中显示特定小部件的子小部件?

Flutter/Dart 如何将索引从 Listview.builder 传递到项目小部件

Flutter中如何检测ListView的滚动位置

如何在 Flutter 的同一屏幕中管理两个带有数据的 ListView