问题
I have a list of locations I retrieve and display in a Listview Builder.
Each location has a latitude and longitude value.
Am now trying to include a "distance" field to the Listview using the GeoLocator Plugin (https://pub.dartlang.org/packages/geolocator) - by having a "Find Nearest" button that gets the user location, then calculates the distance using the user's lat/lon and each location's lat/lon.
Since the "GeoLocator Calculate Distance Method" is asynchronous, I can't insert Geolocator().distanceBetween(userLat, userLon, storeLat, storeLon) directly into the widget.
QUESTION: So how can I do it such that, when the user clicks on the button "Find Nearest", each Listview item is passed through the getDistance method and returns a result?
Simplified Code:
Future<List> getdata() async {
final response = await http.get(getStoreLocations);
return json.decode(response.body);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("Location"),),
body: new FutureBuilder<List>(
future: getdata(),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? new BrowseStoreLocation(
list: snapshot.data,)
: new Center(
child: new CircularProgressIndicator(),
);
},
),
);
}
}
GeoLocator Get User location Method:
getLocation () async {
Position position = await Geolocator().getCurrentPosition(LocationAccuracy.best);
userLat = position.latitude;
userLon = position.longitude;
setState(() {
});
}
GeoLocator Calculate Distance Method:
getDistance()async {
double distanceInMeters = await Geolocator().distanceBetween(userLat,
userLon, storeLat, storeLon);
distance = distanceInMeters/1000;
}
I have tried experimenting by setting variables. The print displayed the storeLat and storeLon values for all items, but only the last listitem was calculated and returned.
String storeLat = "";
String storeLon = "";
getDistance(storeLat,storeLon)async {
double distanceInMeters = await Geolocator().distanceBetween(userLat, userLon, double.parse(storeLat), double.parse(storeLon));
distance = distanceInMeters/1000;
setState(() {
});
}
new ListView.builder(
itemCount: widget.list == null ? 0 : widget.list.length,
itemBuilder: (context, i) {
storeLat = widget.list[i]['latitude'];
storeLon = widget.list[i]['longitude'];
print(storeLon+storeLat);
return Container(
child: Column(
children: <Widget>[
new Text(distance.toString())
],
),
回答1:
You have to use FutureBuilder for this purpose inside your ListView.builder and then have to call your method getDistance
inside that.
ListView.builder(
itemCount: locationsList.length,
itemBuilder: (context, position) {
final current = locationsList[position];
return FutureBuilder<String>(
future: getDistance(current.latitude, current.longitude)
.then((location) => location.toString()),
builder: (context, snapshot) {
return Container(
child: Column(
children: <Widget>[new Text(snapshot.data)],
),
);
});
});
来源:https://stackoverflow.com/questions/52359405/flutter-run-async-function-for-each-listview-item