首页 > 解决方案 > 如何根据flutter中的异步函数返回的与当前用户的距离对列表进行排序?

问题描述

我一直在尝试对对象列表进行排序,代码如下:-

class Locations {
  final GeoPoint location;
  Locations({this.location});
}

class LocationCard extends StatefulWidget {
  final int index;
  LocationCard({this.index});
  @override
  _LocationCardState createState() => _LocationCardState();
}

class _LocationCardState extends State<LocationCard> {
  @override
  Widget build(BuildContext context) {
    final List<Locations> locationlist = [
      Locations(location: GeoPoint(1, 2)),
      Locations(location: GeoPoint(2, 2)),
      Locations(location: GeoPoint(3, 2)),
      Locations(location: GeoPoint(4, 1))
    ]; //list to be sorted
    GeoPoint mylocation = GeoPoint(2, 2);
    double distance;
    var userindex;
    List sorted = [];

    //sort locationlist here

    for (var i = 0; i < sorted.length; i++) {
      if (sorted[i].location == mylocation) {
        userindex = sorted.indexOf(locationlist[i]);
      }
    }//gets user's index in list

    futureconvert() async {
      distance = await Geolocator().distanceBetween(
              sorted[userindex].location.longitude,
              sorted[userindex].location.latitude,
              sorted[widget.index].location.longitude,
              sorted[widget.index].location.latitude) /
          1000;
      return distance;
    }

    return Container(
      child: Card(
        child: Center(
          child: FutureBuilder(
              future: futureconvert(),
              builder: (context, snapshot) {
                return Text(distance.toString());
              }),
        ),
      ),
    );
  }
}

class LocationList extends StatefulWidget {
  @override
  _LocationListState createState() => _LocationListState();
}

class _LocationListState extends State<LocationList> {
  @override
  Widget build(BuildContext context) {
    final List<Locations> locationlist = [
      Locations(location: GeoPoint(1, 2)),
      Locations(location: GeoPoint(2, 2)),
      Locations(location: GeoPoint(3, 2)),
      Locations(location: GeoPoint(4, 1))
    ]; //list to be sorted
    GeoPoint mylocation = GeoPoint(2, 2);//current user location

    List sorted = [];

    //sort locationlist here 

    return ListView.builder(
        scrollDirection: Axis.horizontal,
        itemCount: sorted.length,
        itemBuilder: (context, index) {
          return LocationCard(index: index);
        });
  }
}

我需要一个locationlist根据接近度进行mylocation排序的函数。我尝试使用此函数返回的值进行排序

distancef(var x, var y) async {
      return await Geolocator().distanceBetween(
          locationlist[userindex].location.longitude,
          locationlist[userindex].location.latitude,
          x,
          y);
    }

但看起来我必须编写自己的自定义排序函数,因为我有一个未来的价值作为回报。

我该怎么做呢?

标签: sortingflutterasynchronousdart

解决方案


由于无论如何我们都需要距离,我们可以先将每个位置映射到距离。然后按距离排序。FutureBuilder 可用于构建 ListView。

class LocationList extends StatefulWidget {
  @override
  _LocationListState createState() => _LocationListState();
}

class _LocationListState extends State<LocationList> {
  @override
  Widget build(BuildContext context) {
    // location list and mylocation

    Future<int> distanceFromMyLocation(Locations location) async {
      int distance = await Geolocator().distanceBetween(
              mylocation.location.longitude,
              mylocation.location.latitude,
              location.location.longitude,
              location.location.latitude) /
          1000;
      return distance;
    }

    // Return a list of location and corresponding distance from user
    Future<List<Map<String, dynamic>>> sortByDistance(List<Locations> locationlist) async {

      // make this an empty list by intializing with []
      List<Map<String, dynamic>> locationListWithDistance = [];
  
      // associate location with distance
      for(var location in locationlist) {
        int distance = await distanceFromMyLocation(location);
        locationListWithDistance.add({
          'location': location,
          'distance': distance,
        });
      }

      // sort by distance
      locationListWithDistance.sort((a, b) {
        int d1 = a['distance'];
        int d2 = b['distance'];
        if (d1 > d2) return 1;
        else if (d1 < d2) return -1;
        else return 0;
      });

      return locationListWithDistance;
    }

    return FutureBuilder(
      future: sortByDistance(locationlist),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return CircularProgressIndicator();
        }

        var sorted = snapshot.data as List<Map<String, dynamic>>;

        return ListView.builder(
          scrollDirection: Axis.horizontal,
          itemCount: sorted.length,
          itemBuilder: (context, index) {
            return LocationCard(sorted[index]);
          });
      },
    );
  }
}
class LocationCard extends StatelessWidget {
  final Map<String, dynamic> locationAndDistance;
  LocationCard({this.locationAndDistance});
  
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Card(
        child: Center(
          // location can be accessed by locationAndDistance['location']
          // distance can be accessed by locationAndDistance['distance']
          child: Text(locationAndDistance['distance'].toString());
        ),
      ),
    );
  }
}

推荐阅读