Flutter离线地理编码插件geocoder_offline的使用

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

Flutter离线地理编码插件geocoder_offline的使用

简介

geocoder_offline 是一个用于超快速离线反向地理编码的Dart库。该库使用k-d树来搜索给定文件中的最近位置。一旦Geocoder初始化完成,位置搜索速度非常快,大约在4-5毫秒之间。

数据准备

为了使用反向地理编码库,你需要提供一个包含地点数据的文件。以下是两个示例文件:

  1. GeoNames数据文件,包含全球人口超过15,000的城市。
  2. USGS数据文件,包含美国人口超过5,000的城市。

你可以使用任何其他包含地点名称、纬度和经度的数据文件。

使用方法

1. 导入库

首先,在你的Dart文件中导入 geocoder_offline 库:

import 'package:geocoder_offline/geocoder_offline.dart';

2. 初始化Geocoder

接下来,初始化 GeocodeData 对象。你需要提供一个包含地点数据的文件路径,并指定文件中的列名(如地点名称、州/国家、纬度、经度等)以及分隔符和行结束符。

var geocoder = GeocodeData(
    File('assets/NationalFedCodes_20191101.csv').readAsStringSync(), // 输入字符串
    'FEATURE_NAME', // 地点名称列名
    'STATE_ALPHA', // 州/国家列名
    'PRIMARY_LATITUDE', // 纬度列名
    'PRIMARY_LONGITUDE', // 经度列名
    fieldDelimiter: ',', // 字段分隔符
    eol: '\n'); // 行结束符

3. 反向地理编码

初始化完成后,你可以使用 search 方法进行反向地理编码。传入经纬度坐标,返回一个包含匹配地点的结果列表。

List<LocationResult> result = geocoder.search(41.881832, -87.623177);

完整示例Demo

以下是一个完整的Flutter示例,展示了如何使用 geocoder_offline 插件进行离线反向地理编码。

项目结构

lib/
  main.dart
assets/
  NationalFedCodes_20191101.csv

main.dart

import 'package:flutter/material.dart';
import 'package:geocoder_offline/geocoder_offline.dart';
import 'dart:io';

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Offline Geocoder Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: GeocoderHomePage(),
    );
  }
}

class GeocoderHomePage extends StatefulWidget {
  [@override](/user/override)
  _GeocoderHomePageState createState() => _GeocoderHomePageState();
}

class _GeocoderHomePageState extends State<GeocoderHomePage> {
  late GeocodeData geocoder;
  List<LocationResult>? results;
  bool isLoading = false;

  [@override](/user/override)
  void initState() {
    super.initState();
    _initializeGeocoder();
  }

  Future<void> _initializeGeocoder() async {
    setState(() {
      isLoading = true;
    });

    try {
      // 读取资产文件
      final fileContent = await rootBundle.loadString('assets/NationalFedCodes_20191101.csv');
      
      // 初始化GeocodeData
      geocoder = GeocodeData(
        fileContent, // 输入字符串
        'FEATURE_NAME', // 地点名称列名
        'STATE_ALPHA', // 州/国家列名
        'PRIMARY_LATITUDE', // 纬度列名
        'PRIMARY_LONGITUDE', // 经度列名
        fieldDelimiter: ',', // 字段分隔符
        eol: '\n', // 行结束符
      );

      setState(() {
        isLoading = false;
      });
    } catch (e) {
      print('Error initializing geocoder: $e');
      setState(() {
        isLoading = false;
      });
    }
  }

  void _performReverseGeocoding(double latitude, double longitude) {
    setState(() {
      isLoading = true;
    });

    try {
      // 执行反向地理编码
      List<LocationResult> result = geocoder.search(latitude, longitude);
      setState(() {
        results = result;
        isLoading = false;
      });
    } catch (e) {
      print('Error performing reverse geocoding: $e');
      setState(() {
        isLoading = false;
      });
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Offline Geocoder Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              decoration: InputDecoration(
                labelText: 'Latitude',
                border: OutlineInputBorder(),
              ),
              keyboardType: TextInputType.number,
              onChanged: (value) {
                // 你可以在这里处理输入的纬度值
              },
            ),
            SizedBox(height: 16.0),
            TextField(
              decoration: InputDecoration(
                labelText: 'Longitude',
                border: OutlineInputBorder(),
              ),
              keyboardType: TextInputType.number,
              onChanged: (value) {
                // 你可以在这里处理输入的经度值
              },
            ),
            SizedBox(height: 16.0),
            ElevatedButton(
              onPressed: () {
                // 假设用户输入了41.881832, -87.623177
                _performReverseGeocoding(41.881832, -87.623177);
              },
              child: Text('Perform Reverse Geocoding'),
            ),
            SizedBox(height: 16.0),
            if (isLoading)
              CircularProgressIndicator(),
            if (results != null && !isLoading)
              Expanded(
                child: ListView.builder(
                  itemCount: results!.length,
                  itemBuilder: (context, index) {
                    final result = results![index];
                    return ListTile(
                      title: Text(result.name),
                      subtitle: Text('${result.latitude}, ${result.longitude}'),
                    );
                  },
                ),
              ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter离线地理编码插件geocoder_offline的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter离线地理编码插件geocoder_offline的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中集成和使用geocoder_offline插件的详细步骤,包括相关的代码示例。geocoder_offline插件允许你在离线状态下进行地理编码(从地址到坐标)和逆地理编码(从坐标到地址)。

1. 添加依赖

首先,在你的Flutter项目的pubspec.yaml文件中添加geocoder_offline依赖:

dependencies:
  flutter:
    sdk: flutter
  geocoder_offline: ^最新版本号  # 请替换为最新版本号

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

2. 导入插件

在你的Dart文件中导入geocoder_offline插件:

import 'package:geocoder_offline/geocoder_offline.dart';

3. 初始化并下载离线数据库

在使用geocoder_offline之前,你需要下载并初始化离线数据库。这通常是在应用启动时完成的。

void initGeocoder() async {
  // 检查并下载离线数据库
  bool isDownloaded = await GeocoderOffline.isDatabaseDownloaded();
  if (!isDownloaded) {
    print("Database not downloaded, starting download...");
    await GeocoderOffline.downloadDatabase();
    print("Database downloaded.");
  } else {
    print("Database already downloaded.");
  }

  // 初始化Geocoder
  await GeocoderOffline.initialize();
  print("Geocoder initialized.");
}

确保在调用任何其他地理编码功能之前调用initGeocoder()

4. 地理编码示例

从地址获取坐标:

void getCoordinatesFromAddress() async {
  String address = "1600 Amphitheatre Parkway, Mountain View, CA";
  List<GeocodingResult> results = await GeocoderOffline.getFromLocationName(address);

  if (results.isNotEmpty) {
    GeocodingResult result = results[0];
    double latitude = result.latitude;
    double longitude = result.longitude;
    print("Address: $address");
    print("Latitude: $latitude, Longitude: $longitude");
  } else {
    print("No results found for address: $address");
  }
}

5. 逆地理编码示例

从坐标获取地址:

void getAddressFromCoordinates() async {
  double latitude = 37.4219999;
  double longitude = -122.0840575;
  List<GeocodingResult> results = await GeocoderOffline.getFromLocation(latitude, longitude);

  if (results.isNotEmpty) {
    GeocodingResult result = results[0];
    String address = result.addressLine;
    print("Latitude: $latitude, Longitude: $longitude");
    print("Address: $address");
  } else {
    print("No results found for coordinates: Latitude $latitude, Longitude $longitude");
  }
}

6. 完整示例

将上述代码整合到一个完整的Flutter应用中:

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

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

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

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
    initGeocoder();
  }

  void initGeocoder() async {
    bool isDownloaded = await GeocoderOffline.isDatabaseDownloaded();
    if (!isDownloaded) {
      await GeocoderOffline.downloadDatabase();
    }
    await GeocoderOffline.initialize();
  }

  void _getCoordinatesFromAddress() async {
    String address = "1600 Amphitheatre Parkway, Mountain View, CA";
    List<GeocodingResult> results = await GeocoderOffline.getFromLocationName(address);

    if (results.isNotEmpty) {
      GeocodingResult result = results[0];
      double latitude = result.latitude;
      double longitude = result.longitude;
      print("Address: $address");
      print("Latitude: $latitude, Longitude: $longitude");
    } else {
      print("No results found for address: $address");
    }
  }

  void _getAddressFromCoordinates() async {
    double latitude = 37.4219999;
    double longitude = -122.0840575;
    List<GeocodingResult> results = await GeocoderOffline.getFromLocation(latitude, longitude);

    if (results.isNotEmpty) {
      GeocodingResult result = results[0];
      String address = result.addressLine;
      print("Latitude: $latitude, Longitude: $longitude");
      print("Address: $address");
    } else {
      print("No results found for coordinates: Latitude $latitude, Longitude $longitude");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Geocoder Offline Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Press buttons below to perform geocoding operations'),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _getCoordinatesFromAddress,
              child: Text('Get Coordinates from Address'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _getAddressFromCoordinates,
              child: Text('Get Address from Coordinates'),
            ),
          ],
        ),
      ),
    );
  }
}

确保你已经按照上述步骤正确设置了你的Flutter项目,并且离线数据库已经下载和初始化。然后你可以运行应用,并通过按钮来测试地理编码和逆地理编码功能。

回到顶部