Flutter地理位置排序插件geo_sort的使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter地理位置排序插件geo_sort的使用

Geosort 是一个 Dart 包,用于根据距离参考位置来对地理位置列表进行排序。它提供了计算两个地理坐标之间距离的方法(使用逆向半正矢公式),以及对位置列表按距离进行排序的功能。Geosort 对于需要计算和排序地理位置的应用程序非常有用,例如地图应用、地理位置服务和兴趣点管理。

安装

此包旨在支持 Dart 项目的开发。通常将其添加到 dependencies 下,在您的 pubspec.yaml 文件中:

dependencies:
  geo_sort: ^0.1.0

您可以通过命令行安装包:

pub get

使用

首先,您需要创建一个实现 HasLocation 接口的类,如下所示:

class TestLocation implements HasLocation {
  final int id;
  final String city;
  [@override](/user/override)
  final double latitude;
  [@override](/user/override)
  final double longitude;

  TestLocation({
    required this.id,
    required this.city,
    required this.latitude,
    required this.longitude,
  });
}

然后,创建一个 TestLocation 对象列表:

final List<TestLocation> locations = [
  TestLocation(id: 1, city: 'Rome', latitude: 41.9028, longitude: 12.4964),
  TestLocation(id: 2, city: 'Milan', latitude: 45.4642, longitude: 9.1900),
  TestLocation(id: 3, city: 'Naples', latitude: 40.8518, longitude: 14.2681),
];

现在,您可以使用 GeoSort 类来根据距离从参考位置对位置列表进行排序。以下是具体方法:

final sortedLocations = GeoSort.sortByLatLong(
  items: locations,
  latitude: 41.9028,
  longitude: 12.4964,
  ascending: false,
);

这将按照坐标 (41.9028, 12.4964) 的距离从近到远对位置列表进行排序。

参数解释

  • items: 需要排序的位置列表。
  • latitudelongitude: 参考位置的坐标。
  • ascending: 指示是否按升序(默认)或降序进行排序。
  • maxDistance: 定义在排序列表内包含项的最大距离(以千米为单位)。
  • maxElements: 指定在排序列表内包含的最大元素数量。

这些参数提供了额外的控制,可以根据用户偏好或特定应用程序需求来选择和排序列表中的项。

完整代码

import 'package:geo_sort/src/extensions/extensions.dart';
import 'package:geo_sort/src/utils/utils.dart';

class TestLocation implements HasLocation {
  final int id;
  final String city;
  [@override](/user/override)
  final double latitude;
  [@override](/user/override)
  final double longitude;

  TestLocation({
    required this.id,
    required this.city,
    required this.latitude,
    required this.longitude,
  });
}

void main() {
  // 创建 TestLocation 实例列表
  final List<TestLocation> locations = [
    TestLocation(id: 1, city: 'Rome', latitude: 41.9028, longitude: 12.4964),
    TestLocation(id: 2, city: 'Milan', latitude: 45.4642, longitude: 9.1900),
    TestLocation(id: 3, city: 'Naples', latitude: 40.8518, longitude: 14.2681),
  ];

  // 参考坐标
  final double referenceLat = 41.9028;
  final double referenceLong = 12.4964;

  // 按距离排序
  final sortedLocations = GeoSort.sortByLatLong<TestLocation>(
    items: locations,
    latitude: referenceLat,
    longitude: referenceLong,
    ascending: false,
  );

  // 打印排序后的列表
  print('Sorted Locations:');
  sortedLocations.forEach((location) {
    print('${location.city}: ${location.latitude}, ${location.longitude}');
  });
}

示例应用

以下是一个完整的 Flutter 应用示例,演示如何使用 GeoSort 来对地点列表进行排序:

import 'dart:convert';

/// 一个演示 GeoSort 使用的示例应用,用于根据参考位置的距离对地点列表进行排序。
import 'package:flutter/material.dart';
import 'package:geo_sort/geo_sort.dart';

void main() {
  runApp(const SortApp());
}

class SortApp extends StatelessWidget {
  const SortApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '地点列表顺序排序',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const LocationListScreen(),
    );
  }
}

class LocationListScreen extends StatefulWidget {
  const LocationListScreen({super.key});

  [@override](/user/override)
  State<LocationListScreen> createState() => _LocationListScreenState();
}

class _LocationListScreenState extends State<LocationListScreen> {
  // 意大利地点列表及其经纬度
  List<Location> _italianLocations = [
    Location(
        id: 1,
        name: 'Roma',
        city: '罗马',
        latitude: 41.9028,
        longitude: 12.4964),
    Location(
        id: 2,
        name: 'Milano',
        city: '米兰',
        latitude: 45.4642,
        longitude: 9.1900),
    Location(
        id: 3,
        name: 'Napoli',
        city: '那不勒斯',
        latitude: 40.8518,
        longitude: 14.2681),
    Location(
        id: 4,
        name: 'Torino',
        city: '都灵',
        latitude: 45.0703,
        longitude: 7.6869),
    Location(
        id: 5,
        name: 'Palermo',
        city: '巴勒莫',
        latitude: 38.1157,
        longitude: 13.3615),
    Location(
        id: 6,
        name: 'Genova',
        city: '热那亚',
        latitude: 44.4056,
        longitude: 8.9463),
    Location(
        id: 7,
        name: 'Bologna',
        city: '博洛尼亚',
        latitude: 44.4949,
        longitude: 11.3426),
    Location(
        id: 8,
        name: 'Firenze',
        city: '佛罗伦萨',
        latitude: 43.7696,
        longitude: 11.2558),
    Location(
        id: 9,
        name: 'Bari',
        city: '巴里',
        latitude: 41.1171,
        longitude: 16.8719),
    Location(
        id: 10,
        name: 'Catania',
        city: '卡塔尼亚',
        latitude: 37.5079,
        longitude: 15.0830),
    Location(
        id: 11,
        name: 'Venezia',
        city: '威尼斯',
        latitude: 45.4408,
        longitude: 12.3155),
    Location(
        id: 12,
        name: 'Verona',
        city: '维罗纳',
        latitude: 45.4384,
        longitude: 10.9916),
    Location(
        id: 13,
        name: 'Messina',
        city: '墨西拿',
        latitude: 38.1938,
        longitude: 15.5540),
    Location(
        id: 14,
        name: 'Padova',
        city: '帕多瓦',
        latitude: 45.4064,
        longitude: 11.8768),
    Location(
        id: 15,
        name: 'Trieste',
        city: '的里雅斯特',
        latitude: 45.6495,
        longitude: 13.7768),
    Location(
        id: 16,
        name: 'Taranto',
        city: '塔兰托',
        latitude: 40.4786,
        longitude: 17.2394),
    Location(
        id: 17,
        name: 'Brescia',
        city: '布雷西亚',
        latitude: 45.5398,
        longitude: 10.2227),
    Location(
        id: 18,
        name: 'Reggio di Calabria',
        city: '卡拉布里亚雷焦',
        latitude: 38.1147,
        longitude: 15.6500),
    Location(
        id: 19,
        name: 'Modena',
        city: '摩德纳',
        latitude: 44.6471,
        longitude: 10.9252),
    Location(
        id: 20,
        name: 'Prato',
        city: '普拉托',
        latitude: 43.8777,
        longitude: 11.1027),
  ];

  final TextEditingController _latitudeController = TextEditingController(text: '37.074153');
  final TextEditingController _longitudeController = TextEditingController(text: '14.240354');

  bool _ascending = true;
  void _sortLocations(bool ascending) {
    final latitude = _latitudeController.text.isNotEmpty
        ? double.parse(_latitudeController.text)
        : 41.9028;
    final longitude = _longitudeController.text.isNotEmpty
        ? double.parse(_longitudeController.text)
        : 12.4964;

    setState(() {
      _ascending = ascending;
      _italianLocations = GeoSort.sortByLatLong<Location>(
        items: _italianLocations,
        latitude: latitude,
        longitude: longitude,
        ascending: _ascending,
      );
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('地点列表'),
      ),
      body: SafeArea(
        child: Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: _italianLocations.length,
                itemBuilder: (context, index) {
                  final location = _italianLocations[index];
                  return ListTile(
                    title: Text(location.name),
                    subtitle: Text(location.city),
                    // 如有必要,添加其他信息
                  );
                },
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  ElevatedButton(
                    onPressed: () => _sortLocations(true),
                    child: const Text('升序排序'),
                  ),
                  ElevatedButton(
                    onPressed: () => _sortLocations(false),
                    child: const Text('降序排序'),
                  ),
                ],
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Row(
                children: [
                  Expanded(
                    child: TextField(
                      controller: _latitudeController,
                      decoration: const InputDecoration(labelText: '纬度'),
                      keyboardType: const TextInputType.numberWithOptions(decimal: true),
                    ),
                  ),
                  const SizedBox(width: 8.0),
                  Expanded(
                    child: TextField(
                      controller: _longitudeController,
                      decoration: const InputDecoration(labelText: '经度'),
                      keyboardType: const TextInputType.numberWithOptions(decimal: true),
                    ),
                  ),
                ],
              ),
            ),
            ElevatedButton(
              onPressed: () {
                // 处理添加新位置的操作
              },
              child: const Text('添加位置'),
            ),
          ],
        ),
      ),
    );
  }
}

/// 表示带有纬度和经度的地点的模型类。
///
/// 此类应实现 [HasLocation] 接口,以确保包含纬度和经度属性。

class Location implements HasLocation {
  final int id;
  final String name;
  final String city;
  [@override](/user/override)
  final double latitude;
  [@override](/user/override)
  final double longitude;

  Location({
    required this.id,
    required this.name,
    required this.city,
    required this.latitude,
    required this.longitude,
  });

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'name': name,
      'city': city,
      'latitude': latitude,
      'longitude': longitude,
    };
  }

  factory Location.fromMap(Map<String, dynamic> map) {
    return Location(
      id: map['id']?.toInt() ?? 0,
      name: map['name'] ?? '',
      city: map['city'] ?? '',
      latitude: map['latitude']?.toDouble() ?? 0.0,
      longitude: map['longitude']?.toDouble() ?? 0.0,
    );
  }

  String toJson() => json.encode(toMap());

  factory Location.fromJson(String source) => Location.fromMap(json.decode(source));

  [@override](/user/override)
  String toString() {
    return 'Location(id: $id, name: $name, city: $city, latitude: $latitude, longitude: $longitude)';
  }
}

更多关于Flutter地理位置排序插件geo_sort的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter地理位置排序插件geo_sort的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用geo_sort插件来对地理位置进行排序的示例代码。geo_sort插件通常用于根据地理位置(如经纬度)对一组点进行排序,以便按顺序显示或处理这些点。

首先,确保你已经在pubspec.yaml文件中添加了geo_sort依赖:

dependencies:
  flutter:
    sdk: flutter
  geo_sort: ^最新版本号  # 请替换为实际的最新版本号

然后,运行flutter pub get来安装依赖。

接下来,是一个示例代码,展示如何使用geo_sort插件来对一组地点进行排序:

import 'package:flutter/material.dart';
import 'package:geo_sort/geo_sort.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Geo Sort Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<Map<String, double>> locations = [
    {'name': 'Location A', 'latitude': 37.7749, 'longitude': -122.4194},
    {'name': 'Location B', 'latitude': 34.0522, 'longitude': -118.2437},
    {'name': 'Location C', 'latitude': 40.7128, 'longitude': -74.0060},
    // 更多地点...
  ];

  double referenceLatitude = 36.7783; // 参考点的纬度,比如用户的当前位置
  double referenceLongitude = -119.4179; // 参考点的经度

  @override
  Widget build(BuildContext context) {
    List<Map<String, double>> sortedLocations = sortLocations(locations, referenceLatitude, referenceLongitude);

    return Scaffold(
      appBar: AppBar(
        title: Text('Geo Sort Example'),
      ),
      body: ListView.builder(
        itemCount: sortedLocations.length,
        itemBuilder: (context, index) {
          Map<String, double> location = sortedLocations[index];
          return ListTile(
            title: Text('${location['name']}'),
            subtitle: Text('Lat: ${location['latitude'].toStringAsFixed(4)}, Long: ${location['longitude'].toStringAsFixed(4)}'),
          );
        },
      ),
    );
  }

  List<Map<String, double>> sortLocations(List<Map<String, double>> locations, double refLat, double refLong) {
    // 使用 geo_sort 插件的 sortByDistance 方法对地点进行排序
    List<Map<String, double>> sorted = locations.asMap().entries.toList()
      ..sort((a, b) => GeoSort.sortByDistance(
        a.value['latitude'], a.value['longitude'],
        b.value['latitude'], b.value['longitude'],
        refLat, refLong,
      ).compareTo(0));

    // 由于 sortByDistance 返回的是距离差值,我们需要根据距离差值的正负来确定顺序
    // 这里我们按照距离从小到大排序,如果需要从大到小,只需将 compareTo(0) 改为 compareTo(0).reversed
    sorted.sort((a, b) => (
      GeoSort.sortByDistance(
        a['latitude'], a['longitude'],
        refLat, refLong,
      ) - GeoSort.sortByDistance(
        b['latitude'], b['longitude'],
        refLat, refLong,
      )
    ).compareTo(0));

    // 转换回只包含值的列表
    return sorted.map((e) => e.value).toList();
  }
}

在这个示例中,我们有一个包含多个地点的列表,每个地点都有名称、纬度和经度。我们使用geo_sort插件的sortByDistance方法计算每个地点相对于参考点(例如用户的当前位置)的距离,并根据这些距离对地点进行排序。

请注意,geo_sort插件的sortByDistance方法返回的是距离差值,所以我们使用了一个额外的排序步骤来确保地点按照距离从小到大的顺序排列。

此外,你可能需要根据实际插件的版本和API调整代码。如果geo_sort插件的API有所变化,请参考其官方文档进行相应调整。

回到顶部