0

I have declared a text widget as follows:

Text userText = Text("user not found");

I return the widget in my build widget as follows:

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        RepaintBoundary(
          child: userText,
          key: textKey
        ),
        .....

It's inside of a RepaintBoundary because I will transform this widget to a BitmapDescriptor to use it as a marker on my google map.

Then I have the following function to create the markers:

  Future<void> getData() async {
    var map = new Map();
    
    QuerySnapshot querySnapshot = await firestore.collection("users").get(); //get the data
    querySnapshot.docs.forEach((element) { 
      print("Data: ${element.data()['user_uid']}");
      map[element.data()['user_uid']] = element.data()['location']['geopoint'];
    });
    print("-Map- => ${map}");
    
    int id = 0;
    for(var entry in map.entries) {
      _user = entry.key;
      userText = Text('${entry.key}');
      print("USER TEXT: " + userText.toString());
      GeoPoint geo = entry.value;
      print("USER: " + _user);
      print("LOCATION: " + geo.latitude.toString() + " , " + geo.longitude.toString());
      
      BitmapDescriptor testIcon = await getCustomIcon(textKey); //this transforms the Text widget into a BitmapDescriptor
      _markers.add(
        Marker(
          markerId: new MarkerId(id.toString()),
          position: new LatLng(geo.latitude, geo.longitude),
          icon: testIcon
        )
      );
      print("MARKERS IN FOREACH: " + _markers.toString());
      id++;
    }
    print("Map: ${map}");
    setState(() {});
  }

In my Firestore database I have two documents, both with a user_uid and location field. The output of this function is as follows:

I/flutter (13998): USER TEXT: Text("JTtxo8zgjAcsLbTgg753TOacD6R2")
I/flutter (13998): USER: JTtxo8zgjAcsLbTgg753TOacD6R2
I/flutter (13998): LOCATION: 52 , 4
I/flutter (13998): USER TEXT: Text("eBpkVzUPRLPUJHfDyfdo918UcIn1")
I/flutter (13998): USER: eBpkVzUPRLPUJHfDyfdo918UcIn1
I/flutter (13998): LOCATION: 53 , 4

This is exactly what I want. Everything seems to be working. However, on my map there is one marker with the text user not found and there is one marker with the text JTtxo8zgjAcsLbTgg753TOacD6R2. And next to that, the marker with the text JTtxo8zgjAcsLbTgg753TOacD6R2 is on the location 53, 4, and the marker with the text user not found is on the location 52, 4.

So what I'm thinking is that everything works, except that the Text widget is showing the "previous" text. What is the reason for this?

If there's anything unclear, please let me know!

Jip Harthoorn
  • 292
  • 1
  • 8
  • 25
  • Maybe there is a problem with your UI code, I mean you may use wrong index in your map widget. – Alireza Abiri Apr 26 '21 at 10:05
  • @AlirezaAbiri you mean in my `var map`? But then it wouldn't show the correct info in the for loop right? Which it does, it's logging the correct things. – Jip Harthoorn Apr 26 '21 at 11:39
  • Could you provide full code? – Adelina Apr 26 '21 at 12:41
  • @Nuts https://pastebin.com/NJYwyvx5 here you go. I've provided a for-loop which doesn't use my database, it has the same problem. It will look like this https://i.gyazo.com/6cf3b0366878d8de45d6e0260ad54ff7.jpg – Jip Harthoorn Apr 26 '21 at 13:03
  • I think you need to set in in the `setState` function. Now you have an empty set state – Robin Dijkhof Apr 26 '21 at 20:30
  • @RobinDijkhof I thought that it wouldn't matter if I'd put setState afterwards since everything is updated by then and it would be more efficient than updating the state every iteration in the loop. To test it, I've wrapped `userText` with `SetState`. The result is now different but still really weird: https://i.gyazo.com/f7f730a7aadd497630507e74917928b0.jpg. Where exactly do you suggest putting the `SetState` function? – Jip Harthoorn Apr 26 '21 at 21:08
  • It does not matter where you call it. As long as you change the value you want to change on the screen INSIDE the setState function – Robin Dijkhof Apr 26 '21 at 21:22
  • @RobinDijkhof so in the case of the for loop from https://pastebin.com/NJYwyvx5 lines 84-95, would that mean everything of the for loop should be in `SetState`? – Jip Harthoorn Apr 26 '21 at 21:31
  • You can create a temp value: `String tempUser = ""; for....; setState(userText = Text(tempUser))` – Robin Dijkhof Apr 26 '21 at 21:44
  • @RobinDijkhof do you mean like this? https://pastebin.com/NPVvUf61 – Jip Harthoorn Apr 26 '21 at 21:56

1 Answers1

1

Check this gist: https://gist.github.com/itsJoKr/ce5ec57bd6dedf74d1737c1f39481913

And in your code:

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

  getData();
}

Future<void> getData() async {
  List<Widget> widgets = [];

  for (int i = 0; i < 5; i++) {
    widgets.add(Text("Number: $i"));
  }

  MarkerGenerator(
    widgets,
    (bitmaps) {
      for (int i = 0; i < 5; i++) {
        _markers.add(Marker(
          markerId: new MarkerId(i.toString()),
          position:
              new LatLng(52.08674971530128 + i / 1000, 4.269159032232106),
          icon: BitmapDescriptor.fromBytes(bitmaps[i]),
        ));
      }
      setState(() {});
    },
  ).generate(context);

  print("Markers: $_markers");
}

Edit:

Because it waits until the images are loaded, sometimes afterFirstLayout is not called, you should change it to this:

class MarkerGenerator {
...
void generate(BuildContext context) {
  if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
    SchedulerBinding.instance.addPostFrameCallback((_) => afterFirstLayout(context));
  } else {
    afterFirstLayout(context);
  }
}
Luis A. Chaglla
  • 580
  • 4
  • 8
  • Wow this actually works! Thanks a lot. I'm struggling with one more thing. I want to display `CircleAvatar` widgets instead of `Text` (it was for testing), but the images don't show up. I think the markers are made before the NetworkImage is loaded. So I tried to wait untill the image is loaded and then execute the funtion using this code: https://stackoverflow.com/a/59409238/10054433. It didnt work unfortunately. If I create the widget the normal way, it works, but as a marker it doesn't. I do see the circles, but no images. This is the code: https://pastebin.com/K1YqjfGb – Jip Harthoorn Apr 28 '21 at 22:25
  • An addition to my previous comment: line 14 of the pastebin code should contain the `_image` variable instead of the`imageTest` variable. Now that I've done that, it doesn't show any markers but when I quick reload the application with `R`, it shows the markers with the images, but when I hot reload, it doesn't? – Jip Harthoorn Apr 28 '21 at 22:33
  • I've changed my code a little bit. Ultimately, I want to get all profilepictures from my Firestore database and put them on the map as marker. Initially, the markers don't show up. If I hot reload, I can see the markers, but one marker doesn't have an image. I'm sure that the image url is correct of the image that doesn't load. This is the code https://pastebin.com/G3KufkN4 and this is how it looks like (after hot reloading): https://gyazo.com/a3a1d3665c9dd40f0a2cd41708460717 – Jip Harthoorn Apr 29 '21 at 13:15
  • What about this: https://pastebin.com/rcmuJn4T https://gyazo.com/ef735efa9e32f274e23e35de03d3272e (I'm using fake data.) Just wait until all images are loaded. – Luis A. Chaglla Apr 29 '21 at 17:04
  • Thanks that works better already. The images load now but only after hot reloading. Do you experience this aswell? So the application starts without markers but when I hit R, they load. I also experience that when the app loads and I immediately hit R, the markers don't load, but when I wait a couple of seconds and then hit R, all markers load. – Jip Harthoorn Apr 29 '21 at 19:37
  • I didn't experience that with my example. How many markers have you? Maybe it is related. Could you share the updated code on Pastebin? – Luis A. Chaglla Apr 30 '21 at 09:56
  • I am currently testing it with two markers. This is the code I am using https://pastebin.com/sSDLC30X – Jip Harthoorn Apr 30 '21 at 12:16
  • In my last Pastebin, the function generate of MarkerGenerator was modified, did you modify it in your code as well? – Luis A. Chaglla Apr 30 '21 at 12:24
  • Oh I didn't know that, it actually works now! I'm really happy with this thank you so much. Did you modify this yourself? What was the problem? I gave you the 50 points btw ;) – Jip Harthoorn Apr 30 '21 at 12:36
  • The problem was the function was not called in the first time. I updated the answer with a better solution. – Luis A. Chaglla Apr 30 '21 at 13:23
  • The code has an error for me: https://gyazo.com/d0f99ba63e4e7ffc6facc7076bc9b6ae – Jip Harthoorn Apr 30 '21 at 13:59
  • Hey sorry for hitting you up again, but I'm trying to load the markers one by one instead of showing them all at the same time, so you don't have to wait for everything to load. I've put everything in my `for(var element in querySnapshot.docs) {` so that I have access to all the user attributes. I use those in my marker in the `OnTap` event. My question is, the markers (circleAvatars) are really big, and when I change the radius of the circleAvatar or the width of the container above it, nothing changes. Also, is this an efficient way to do this? This is the code https://pastebin.com/ftjYY0Bf – Jip Harthoorn May 03 '21 at 10:36
  • There's another problem, when I zoom out, the markers precision get's worse. The markers move up when I zoom out like this: https://i.gyazo.com/b7c64a0dc4c93a15138d36906c944df1.gif – Jip Harthoorn May 04 '21 at 14:28