插件介绍

flutter_maps_firestore 是一个基于 Flutter 开发的地图应用,它将 Google Maps 与 Firebase Firestore 集成,允许开发者创建显示地理数据的交互式地图应用。该应用展示了如何从 Firestore 加载数据并在 Google Maps 上可视化,同时提供了自定义的用户界面组件来增强用户体验。该插件已适配鸿蒙系统,可以在鸿蒙设备上流畅运行。

主要功能特点:

  • 从 Firebase Firestore 加载地理数据
  • 在 Google Maps 上显示标记点
  • 提供自定义的商店轮播组件
  • 支持地图与列表之间的交互
  • 适配鸿蒙系统,提供一致的用户体验

如何在鸿蒙上使用

1. 引入依赖

由于这是一个自定义修改版本,需要以 git 形式引入。在你的鸿蒙项目的 pubspec.yaml 文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  cloud_firestore: ^4.6.0
  firebase_core: ^2.11.0
  google_maps_flutter: ^2.2.6
  google_maps_webservice: ^0.0.20-nullsafety.5
  location: ">=4.4.0 <6.0.0"
  flutter_maps_firestore:
    git:
      url: "https://github.com/flutter/samples.git"
      path: "flutter_maps_firestore"

2. 配置 API 密钥

该插件需要配置两个 API 密钥:

Google Maps SDK API 密钥

对于 iOS 平台,需要在 ios/Runner/AppDelegate.m 中添加 Google Maps SDK API 密钥。

对于鸿蒙平台,需要在应用的配置文件中添加相应的 API 密钥配置。

Google Maps Web Services API 密钥

创建 lib/api_key.dart 文件,并添加以下内容:

// lib/api_key.dart

const String googleMapsApiKey = 'YOUR_GOOGLE_MAPS_WEB_SERVICE_API_KEY';

注意:在生产环境中,不应该将 Web Service API 密钥直接放在应用二进制文件中。应该构建一个代理服务来为移动应用提供预认证的内容,以便可以根据需要更改 API 密钥。

3. 配置 Firebase Firestore

设置 Firebase 项目
  1. 访问 Firebase 控制台
  2. 创建一个新的 Firebase 项目
  3. 在项目设置中添加鸿蒙应用
  4. 下载 google-services.json 文件并将其放置在适当的位置
准备 Firestore 数据

在 Firestore 中创建一个名为 ice_cream_stores 的集合,并添加以下结构的文档:

ice_cream_stores:
  ChIJ70taCKKAhYAR5IMmYwQT4Ts:
    placeId: ChIJ70taCKKAhYAR5IMmYwQT4Ts
    address: 432 Octavia St #1a, San Francisco, CA 94102, USA
    location: GeoPoint(37.7763629, -122.4241918)
    name: Smitten Ice Cream

4. API 调用示例

初始化 Firebase
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(const MyApp());
}
加载 Firestore 数据
late Stream<QuerySnapshot> _iceCreamStores;


void initState() {
  super.initState();
  _iceCreamStores = FirebaseFirestore.instance
      .collection('ice_cream_stores')
      .orderBy('name')
      .snapshots();
}
创建 Google 地图
class StoreMap extends StatelessWidget {
  const StoreMap({
    super.key,
    required this.documents,
    required this.initialPosition,
    required this.mapController,
  });

  final List<DocumentSnapshot> documents;
  final LatLng initialPosition;
  final Completer<GoogleMapController> mapController;

  
  Widget build(BuildContext context) {
    return GoogleMap(
      initialCameraPosition: CameraPosition(
        target: initialPosition,
        zoom: 12,
      ),
      markers: documents
          .map((document) => Marker(
                markerId: MarkerId(document['placeId'] as String),
                icon: BitmapDescriptor.defaultMarkerWithHue(350.0), // Pink hue
                position: LatLng(
                  document['location'].latitude as double,
                  document['location'].longitude as double,
                ),
                infoWindow: InfoWindow(
                  title: document['name'] as String?,\n                  snippet: document['address'] as String?,\n                ),\n              ))\n          .toSet(),\n      onMapCreated: (mapController) {
        this.mapController.complete(mapController);\n      },\n    );
  }
}
创建商店轮播
class StoreCarousel extends StatelessWidget {
  const StoreCarousel({
    super.key,
    required this.documents,
    required this.mapController,
  });

  final List<DocumentSnapshot> documents;
  final Completer<GoogleMapController> mapController;

  
  Widget build(BuildContext context) {
    return Align(
      alignment: Alignment.topLeft,
      child: Padding(
        padding: const EdgeInsets.only(top: 10),
        child: SizedBox(
          height: 90,
          child: ListView.builder(
            scrollDirection: Axis.horizontal,
            itemCount: documents.length,
            itemBuilder: (context, index) {
              return SizedBox(
                width: 340,
                child: Padding(
                  padding: const EdgeInsets.only(left: 8),
                  child: Card(
                    child: ListTile(
                      title: Text(documents[index]['name'] as String),
                      subtitle: Text(documents[index]['address'] as String),
                      onTap: () async {
                        final controller = await mapController.future;
                        await controller.animateCamera(
                          CameraUpdate.newCameraPosition(
                            CameraPosition(
                              target: LatLng(
                                documents[index]['location'].latitude as double,
                                documents[index]['location'].longitude as double,
                              ),
                              zoom: 16,
                            ),
                          ),
                        );
                      },
                    ),
                  ),
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}

5. 完整应用示例

import 'dart:async';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

import 'api_key.dart';

// 地图初始位置
const initialPosition = LatLng(37.7786, -122.4375);

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(const App());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Maps Firestore',
      home: const HomePage(title: 'Ice Cream Stores'),
      theme: ThemeData(
        colorSchemeSeed: Colors.pink,
        scaffoldBackgroundColor: Colors.pink[50],
        useMaterial3: true,
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({required this.title, super.key});
  final String title;

  
  State<StatefulWidget> createState() {
    return _HomePageState();
  }
}

class _HomePageState extends State<HomePage> {
  late Stream<QuerySnapshot> _iceCreamStores;
  final Completer<GoogleMapController> _mapController = Completer();

  
  void initState() {
    super.initState();
    _iceCreamStores = FirebaseFirestore.instance
        .collection('ice_cream_stores')
        .orderBy('name')
        .snapshots();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: StreamBuilder<QuerySnapshot>(
        stream: _iceCreamStores,
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return Center(child: Text('Error: ${snapshot.error}'));
          }
          if (!snapshot.hasData) {
            return const Center(child: Text('Loading...'));
          }
          return Stack(
            children: [
              StoreMap(
                documents: snapshot.data!.docs,
                initialPosition: initialPosition,
                mapController: _mapController,
              ),
              StoreCarousel(
                mapController: _mapController,
                documents: snapshot.data!.docs,
              ),
            ],
          );
        },
      ),
    );
  }
}

总结

flutter_maps_firestore 是一个功能强大的 Flutter 应用,它展示了如何将 Google Maps 与 Firebase Firestore 集成,创建交互式地图应用。该应用提供了以下核心功能:

  1. 从 Firebase Firestore 加载地理数据
  2. 在 Google Maps 上显示带有自定义标记的位置
  3. 提供商店轮播组件,允许用户快速导航到特定位置
  4. 支持地图与列表之间的交互

在鸿蒙系统上使用该应用,需要进行以下步骤:

  1. 以 git 形式引入依赖
  2. 配置 Google Maps API 密钥
  3. 设置 Firebase 项目和 Firestore 数据
  4. 初始化 Firebase 并加载数据
  5. 创建地图和商店轮播组件

该应用为开发者提供了一个很好的示例,展示了如何在鸿蒙系统上构建基于地图的应用,并与云服务集成。

欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐