flutterstateupdatesiconbuttonpaginateddatatable

How can I make the iconbutton contained in the datacell display different icons according to the state?


I used a PaginatedDataTable to include several iconbuttons in the Datacell. After clicking the iconbutton, I modified the value of rows[index]['status']. I want the iconbutton's icon to be displayed according to the value of rows[index]['status'].


    import 'package:flutter/material.dart';
    
    List<Map<String, dynamic>> devData() {
      List<Map<String, dynamic>> data = [];
      for (var i = 1; i < 15; i++) {
        data.add({
          'username': 'account$i',
          'nickname': i % 2 == 0 ? 'Peter$i' : 'Charles$i',
          'status': i % 2 == 0 ? 0 : 1,
          'group': i % 2 == 0 ? 2 : 3,
        });
      }
      return data;
    }
    
    List<Map<String, dynamic>> rows = devData();
    
    
    class UserManagePage extends StatefulWidget {
      const UserManagePage({super.key});
    
      @override
      State<StatefulWidget> createState() => UserManagePageState();
    }
    
    class UserManagePageState extends State<UserManagePage> {
      UserManagePageState() {
        rows = devData();
      }
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
              leading: IconButton(
                hoverColor: Colors.transparent,
                onPressed: () {
                  Navigator.pop(context);
                },
                icon: const Icon(Icons.arrow_back_ios_new),
                iconSize: 16,
                color: const Color.fromRGBO(100, 100, 100, 0.5),
              ),
              centerTitle: true,
              automaticallyImplyLeading: false,
              backgroundColor: WidgetStateColor.transparent,
              title: const Text('用户管理',
                  style: TextStyle(
                      fontFamily: 'AlimamaFangYuanTi', fontSize: 18, fontWeight: FontWeight.w900))),
          body: Container(
              padding: const EdgeInsets.all(5),
              alignment: const Alignment(0, 0),
              child: PaginatedDataTable(
                horizontalMargin: 5,
                columnSpacing: 30,
                header: Row(children: [
                  IconButton(
                      onPressed: () {
                        showDialog(
                            context: context,
                            builder: (context) {
                              return const UserAdd();
                            });
                      },
                      icon: const Icon(Icons.person_add_alt_1))
                ]),
                columns: const [
                  DataColumn(label: Flexible(child: Center(child: Text('Account')))),
                  DataColumn(label: Flexible(child: Center(child: Text('Username')))),
                  DataColumn(label: Flexible(child: Center(child: Text('Group')))),
                  DataColumn(label: Flexible(child: Center(child: Text('Operation'))))
                ],
                source: UserManageDate(context: context),
              )),
        );
      }
    }
    
    class UserManageDate extends DataTableSource {
      BuildContext context;
    
      UserManageDate({required this.context});
    
      @override
      DataRow? getRow(int index) {
        List<String> groups = ['Super Admin', 'Admin', 'Doctor', 'Nurse'];
        return DataRow(cells: [
          DataCell(Text('${rows[index]['username']}')),
          DataCell(Text('${rows[index]['nickname']}')),
          DataCell(Text(groups[rows[index]['group']])),
          DataCell(
              Flex(
                direction: Axis.horizontal,
                children: [
                  IconButton(
                    onPressed: () {},
                    icon: const Icon(
                      Icons.edit,
                      size: 20,
                      color: Colors.green,
                    ),
                  ),
                  //edit
                  IconButton(
                    onPressed: () {
                      rows[index]['status'] = rows[index]['status'] == 1 ? 0 : 1;
                      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          content: Text(rows[index]['status'] == 1 ? 'Enabled' : 'Disabled'),
                          action: SnackBarAction(label: 'Action', onPressed: () {}),
                          duration: const Duration(milliseconds: 500)));
                    },
                    icon: Icon(
                      rows[index]['status'] == 1 ? Icons.lock : Icons.lock_open_rounded,
                      size: 20,
                      color: rows[index]['status'] == 1 ? Colors.blue : Colors.grey,
                    ),
                  ),
                  //enable/disable
                  IconButton(
                    onPressed: () {},
                    icon: const Icon(
                      Icons.delete,
                      size: 20,
                      color: Colors.grey,
                    ),
                  )
                  //delete:soft delete
                ],
              ), onTap: () {
            print('11111222');
          })
        ]);
      }
    
      @override
      // TODO: implement isRowCountApproximate
      bool get isRowCountApproximate => false;
    
      @override
      // TODO: implement rowCount
      int get rowCount => rows.length;
    
      @override
      // TODO: implement selectedRowCount
      int get selectedRowCount => 0;
    }

This all my code.

IconButton(
                onPressed: () {
                  rows[index]['status'] = rows[index]['status'] == 1 ? 0 : 1;
                  ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                      content: Text(rows[index]['status'] == 1 ? 'Enabled' : 'Disabled'),
                      action: SnackBarAction(label: 'Action', onPressed: () {}),
                      duration: const Duration(milliseconds: 500)));
                },
                icon: Icon(
                  rows[index]['status'] == 1 ? Icons.lock : Icons.lock_open_rounded,
                  size: 20,
                  color: rows[index]['status'] == 1 ? Colors.blue : Colors.grey,
                ),
              ),

1.When click this button update rows[index]['status'] value,but the screen is not update.


Solution

  • when data changes, you need to use setState to update the state; otherwise, the page will not refresh. However, you are using a stateless widget, so you cannot use setState. Therefore, I recommend using Provider for state management. Here is a demo with your code modified accordingly.

    import 'package:flutter/material.dart';
    import 'dart:ui' as ui;
    import 'package:provider/provider.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class UserDataProvider extends ChangeNotifier {
      List<Map<String, dynamic>> _rows = [];
    
      UserDataProvider() {
        _initializeData();
      }
    
      List<Map<String, dynamic>> get rows => _rows;
    
      void _initializeData() {
        for (var i = 1; i < 15; i++) {
          _rows.add({
            'username': 'account$i',
            'nickname': i % 2 == 0 ? 'Peter$i' : 'Charles$i',
            'status': i % 2 == 0 ? 0 : 1,
            'group': i % 2 == 0 ? 2 : 3,
          });
        }
        notifyListeners();
      }
    
      void updateStatus(int index) {
        _rows[index]['status'] = _rows[index]['status'] == 1 ? 0 : 1;
        notifyListeners();
      }
    }
    
    class UserManagePage extends StatefulWidget {
      const UserManagePage({super.key});
    
      @override
      State<StatefulWidget> createState() => UserManagePageState();
    }
    
    class UserManagePageState extends State<UserManagePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
              leading: IconButton(
                hoverColor: Colors.transparent,
                onPressed: () {
                  Navigator.pop(context);
                },
                icon: const Icon(Icons.arrow_back_ios_new),
                iconSize: 16,
                color: const Color.fromRGBO(100, 100, 100, 0.5),
              ),
              centerTitle: true,
              automaticallyImplyLeading: false,
              backgroundColor: Colors.transparent,
              title: const Text('用户管理',
                  style: TextStyle(
                      fontFamily: 'AlimamaFangYuanTi',
                      fontSize: 18,
                      fontWeight: FontWeight.w900))),
          body: Container(
              padding: const EdgeInsets.all(5),
              alignment: const Alignment(0, 0),
              child: Consumer<UserDataProvider>(
                builder: (context, userDataProvider, child) {
                  return PaginatedDataTable(
                    horizontalMargin: 5,
                    columnSpacing: 30,
                    header: Row(children: [
                      IconButton(
                          onPressed: () {
                            showDialog(
                                context: context,
                                builder: (context) {
                                  return AlertDialog(
                                      title: const Text('Add User'),
                                      content: const Text('Add User'),
                                      actions: [
                                        TextButton(
                                            onPressed: () {
                                              Navigator.pop(context);
                                            },
                                            child: const Text('Cancel')),
                                        TextButton(
                                            onPressed: () {
                                              Navigator.pop(context);
                                            },
                                            child: const Text('Add'))
                                      ]);
                                });
                          },
                          icon: const Icon(Icons.person_add_alt_1))
                    ]),
                    columns: const [
                      DataColumn(
                          label: Flexible(child: Center(child: Text('Account')))),
                      DataColumn(
                          label: Flexible(child: Center(child: Text('Username')))),
                      DataColumn(
                          label: Flexible(child: Center(child: Text('Group')))),
                      DataColumn(
                          label: Flexible(child: Center(child: Text('Operation'))))
                    ],
                    source: UserManageData(userDataProvider.rows, context),
                  );
                },
              )),
        );
      }
    }
    
    class UserManageData extends DataTableSource {
      final List<Map<String, dynamic>> rows;
      final BuildContext context;
    
      UserManageData(this.rows, this.context);
    
      @override
      DataRow? getRow(int index) {
        List<String> groups = ['Super Admin', 'Admin', 'Doctor', 'Nurse'];
        return DataRow(cells: [
          DataCell(Text('${rows[index]['username']}')),
          DataCell(Text('${rows[index]['nickname']}')),
          DataCell(Text(groups[rows[index]['group']])),
          DataCell(
              Flex(
                direction: Axis.horizontal,
                children: [
                  IconButton(
                    onPressed: () {},
                    icon: const Icon(
                      Icons.edit,
                      size: 20,
                      color: Colors.green,
                    ),
                  ),
                  //edit
                  IconButton(
                    onPressed: () {
                      Provider.of<UserDataProvider>(context, listen: false)
                          .updateStatus(index);
                      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          content: Text(
                              rows[index]['status'] == 1 ? 'Enabled' : 'Disabled'),
                          action: SnackBarAction(label: 'Action', onPressed: () {}),
                          duration: const Duration(milliseconds: 500)));
                    },
                    icon: Icon(
                      rows[index]['status'] == 1
                          ? Icons.lock
                          : Icons.lock_open_rounded,
                      size: 20,
                      color: rows[index]['status'] == 1 ? Colors.blue : Colors.grey,
                    ),
                  ),
                  //enable/disable
                  IconButton(
                    onPressed: () {},
                    icon: const Icon(
                      Icons.delete,
                      size: 20,
                      color: Colors.grey,
                    ),
                  )
                  //delete:soft delete
                ],
              ), onTap: () {
            print('11111222');
          })
        ]);
      }
    
      @override
      bool get isRowCountApproximate => false;
    
      @override
      int get rowCount => rows.length;
    
      @override
      int get selectedRowCount => 0;
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        // return MaterialApp(
        //   home: BlocProvider(
        //     create: (_) => ColorBloc(),
        //     child: UserManagePage(),
        //   ),
        // );
        return MaterialApp(
          home:  ChangeNotifierProvider(
            create: (context) => UserDataProvider(),
            child: UserManagePage(),
          ),
        );
      }
    }