Search code examples
firebaselistviewflutterdartwidget

How to uniquely identify widgets in flutter?


The feature is to display the profile screen of a user when a specific widget is tapped from a ListView. The way I want to assign each widget with unique ID is to retrieve all IDs from Firebase as an array and create the widgets by iterating through a for loop. Then I add the created widgets to a list and put that list into a ListView. The ListView builds correctly in the application, but I do not know how to add the unique ID's to the widgets in the ListView so that when they are tapped the profile of that widget's ID is retrieve and displayed in a new screen.

I may have the wrong idea about approaching this problem. Because otherwise the IDs will be rendered into the application when the user is using it, which may cause vulnerability issues.

I have tried to use the key property of widgets to store the user unique ID. I also searched the web if there is a way to assign an unique ID to a widget but no luck, or I jam not searching the right way.

enum ScreenStatus {
  NOT_DETERMINED,
  RETRIEVING_FRIEND_LIST,
  FRIEND_LIST_READY,
  FRIEND_PROFILE_OPEN
}

class FriendsScreen extends StatefulWidget {
  FriendsScreen({this.auth});

  final BaseAuth auth;

  @override
  State<StatefulWidget> createState() => _FriendsScreenState();
}

class _FriendsScreenState extends State<FriendsScreen> {
  ScreenStatus screenStatus = ScreenStatus.NOT_DETERMINED;

  List _friendList = [];

  @override
  void initState() {
    super.initState();
    widget.auth.retrieveUserDocument().then((document) {
      document.data.forEach((fieldName, fieldValue) {
        setState(() {
          if (fieldName == 'friends') {
            _friendList = fieldValue;
            print(_friendList);
          }
          screenStatus = _friendList == null
              ? ScreenStatus.RETRIEVING_FRIEND_LIST
              : ScreenStatus.FRIEND_LIST_READY;
        });
      });
    });
  }

  Widget _createFriendListWidget(List friendList) {
    List<Widget> list = List<Widget>();
    for (int i = 0; i < friendList.length; i++) {
      list.add(
        Card(
          child: InkWell(
            onTap: () {
              print('tapped');
            },
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                ListTile(
                  leading: Icon(Icons.album),
                  title: Text(friendList[i]),
                  subtitle: Text('Subtitle'),
                )
              ],
            ),
          ),
        ),
      );
    }
    return ListView(children: list);
  }

  Widget _buildFriendList() {
    return Scaffold(
      body: Container(
        child: _createFriendListWidget(_friendList),
      ),
    );
  }

  Widget _buildWaitingScreen() {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
        child: CircularProgressIndicator(),
      ),
    );
    ;
  }

  @override
  Widget build(BuildContext context) {
    switch (screenStatus) {
      case ScreenStatus.NOT_DETERMINED:
        return _buildWaitingScreen();
        break;
      case ScreenStatus.RETRIEVING_FRIEND_LIST:
        return _buildWaitingScreen();
        break;
      case ScreenStatus.FRIEND_LIST_READY:
        return _buildFriendList();
        break;
      default:
        return _buildWaitingScreen();
    }
  }
}

The expected result is to open a new screen of the profile of the user when the widget is tapped with the respective ID of the user.


Solution

  • I don't think you need to identify widgets. Instead you can use user id in onTap closure

    Here is how updated _createFriendListWidget could look:

      Widget _createFriendListWidget(List friendList) {
        List<Widget> list = List<Widget>();
        for (int i = 0; i < friendList.length; i++) {
          list.add(
            Card(
              child: ListTile(
                leading: Icon(Icons.album),
                title: Text(friendList[i]),
                subtitle: Text('Subtitle'),
                onTap: () {
                  print("tapped ${friendList[i].id}"); // assume that id is in .id field
                }
              ),
            ),
          );
        }
        return ListView(children: list);
      }
    

    Also note that I've removed Column, because it had only one child so it did not have any effect. And I removed Inkwell because ListView can handle onTap too.