如何对StreamBuilder接收的Firestore筛选后数据按距离排序并获取生成的列表?
Hey there! Let's tackle your two requirements one by one—sorting the displayed trips by calculated distance, and accessing the list generated by .toList(). Here's how you can adjust your code to make this work smoothly:
1. Sorting Trips by Calculated Distance
The issue with your current code is that you're generating UI widgets directly while filtering, which leaves no way to collect and sort by the distance value. Instead, we'll first filter and collect valid trips along with their calculated distances, sort that list, then build the UI from the sorted data.
Here's the revised code:
Flexible( child: StreamBuilder<QuerySnapshot>( stream: _usersStream, builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) { if (snapshot.hasError) { return const Text('Error'); } if (snapshot.connectionState == ConnectionState.waiting) { return const Text("Loading"); } // Step 1: Filter valid trips and store them with their calculated distance final validTrips = <Map<String, dynamic>>[]; for (final document in snapshot.data!.docs) { final data = document.data()! as Map<String, dynamic>; final startLocation = data['start_location'] as String; // Skip trips where start location matches the specified place if (startLocation == widget.placename) continue; final coord = data['coord'] as String; final splitted = coord.split('/'); for (int i = 0; i < splitted.length - 1; i++) { final coordPair = splitted[i]; final latLng = coordPair.split('-'); final distance = calculateDistance( widget.place_latlng.latitude, widget.place_latlng.longitude, double.parse(latLng[0]), double.parse(latLng[1]), ); // Add to valid list if distance is under 1 unit (adjust unit if needed) if (distance < 1) { validTrips.add({ ...data, 'distance': distance, // Attach the calculated distance for sorting }); break; // Match your original logic: take first valid coord per document } } } // Step 2: Sort the valid trips by distance (ascending = closest first) validTrips.sort((a, b) => (a['distance'] as double).compareTo(b['distance'] as double)); // Step 3: Build the ListView from the sorted list return ListView( children: validTrips.map((trip) { return GestureDetector( onTap: () { // Your onTap logic here }, child: buildTripCard( context, start_location: trip['start_location'] as String, end_location: trip['end_location'] as String, date: trip['date'] as String, time: trip['time'] as String, price: trip['price'] as String, name_surname: trip['name_surname'] as String, userId: trip['user_id'] as String, ), ); }).toList(), ); }, ), )
Key Notes:
- We first iterate through all Firestore documents, filter out invalid trips, and store valid ones with their calculated distance in the
validTripslist. - The
sortmethod orders trips by distance (closest first). Reverse the comparison (b['distance'].compareTo(a['distance'])) if you want farthest trips first. - The
breakafter adding a valid trip matches your original logic (each document only contributes one trip if any coord meets the distance requirement). Remove it if you need to include multiple entries per document.
2. Accessing the List Generated by .toList()
In the revised code, the validTrips variable is exactly the list you're looking for—it's the filtered, sorted collection of trip data before converting to UI widgets. You can access it directly in the builder function for any additional logic:
// Example: Print the number of valid trips print('Found ${validTrips.length} matching trips'); // Example: Access the first trip's data if (validTrips.isNotEmpty) { print('Closest trip start: ${validTrips.first['start_location']}'); }
If you need to use this list outside the StreamBuilder (e.g., in another method of your widget), store it in a state variable:
- In your
Stateclass, add:List<Map<String, dynamic>>? _sortedTrips; - In the
builderfunction, after sorting:setState(() { _sortedTrips = validTrips; }); - Now you can access
_sortedTripsanywhere in your state class.
内容的提问来源于stack exchange,提问作者Hakan Or

