Flutter自定义地图标记插件custom_map_markers的使用

Flutter 自定义地图标记插件 custom_map_markers 的使用

custom_map_markers 是一个将运行时小部件转换为地图标记图标的包。

特性

此包提供了以下功能:

  • 能够使用 Flutter 小部件创建运行时地图标记。
  • 可以捕获任何小部件列表的图像。

开始使用

首先,在你的 pubspec.yaml 文件中添加 custom_map_markers 作为依赖项。

dependencies:
  custom_map_markers: ^0.0.1

使用方法

  1. 将你的 GoogleMaps 小部件包装在 CustomGoogleMapMarkerBuilder 中。
  2. customMarkers 中定义每个标记及其自定义小部件。
  3. 一旦自定义标记准备好,它们将以 Set<Marker> 形式传递给 builder 函数。
final locations = const [
  LatLng(37.42796133580664, -122.085749655962),
  LatLng(37.41796133580664, -122.085749655962),
];

CustomGoogleMapMarkerBuilder(
  customMarkers: [
    MarkerData(
      marker: Marker(
        markerId: const MarkerId('id-1'),
        position: locations[0],
      ),
      child: _customMarker('A', Colors.black),
    ),
    MarkerData(
      marker: Marker(
        markerId: const MarkerId('id-2'),
        position: locations[1],
      ),
      child: _customMarker('B', Colors.red),
    ),
  ],
  builder: (BuildContext context, Set<Marker>? markers) {
    if (markers == null) {
      return const Center(child: CircularProgressIndicator());
    }
    return GoogleMap(
      initialCameraPosition: const CameraPosition(
        target: LatLng(37.42796133580664, -122.085749655962),
        zoom: 14.4746,
      ),
      markers: markers,
      onMapCreated: (GoogleMapController controller) {},
    );
  },
);

如果你不使用 Google 地图,可以使用 CustomMapMarkerBuilder,它接受 List<Widget> 而不是 List<MarkerData> 并返回 List<Uint8List> 而不是 Set<Marker>。这样你就可以自由地使用捕获的 PNG 图像。

注意事项

  1. 确保你的标记小部件有边界。
  2. 此包在小部件渲染后捕获 PNG 图像。如果您的小部件(如 Image.network)需要更长时间来渲染,您可以使用 screenshotDelay 参数延迟捕获过程,确保小部件正确渲染后再捕获。
  3. 运行项目示例时,您需要向 Android 和 iOS 目录添加有效的 Google 地图密钥。

示例代码

import 'package:custom_map_markers/custom_map_markers.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '自定义标记示例',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: '自定义标记示例'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final locations = const [
    LatLng(37.42796133580664, -122.085749655962),
    LatLng(37.41796133580664, -122.085749655962),
    LatLng(37.43796133580664, -122.085749655962),
    LatLng(37.42796133580664, -122.095749655962),
    LatLng(37.42796133580664, -122.075749655962),
  ];

  late List<MarkerData> _customMarkers;

  [@override](/user/override)
  void initState() {
    super.initState();
    _customMarkers = [
      MarkerData(
        marker: Marker(
          markerId: const MarkerId('id-1'),
          position: locations[0],
        ),
        child: _customMarker3('Everywhere\nis a Widgets', Colors.blue),
      ),
      MarkerData(
        marker: Marker(
          markerId: const MarkerId('id-5'),
          position: locations[4],
        ),
        child: _customMarker('A', Colors.black),
      ),
      MarkerData(
        marker: Marker(
          markerId: const MarkerId('id-2'),
          position: locations[1],
        ),
        child: _customMarker('B', Colors.red),
      ),
      MarkerData(
        marker: Marker(
          markerId: const MarkerId('id-3'),
          position: locations[2],
        ),
        child: _customMarker('C', Colors.green),
      ),
      MarkerData(
        marker: Marker(
          markerId: const MarkerId('id-4'),
          position: locations[3],
        ),
        child: _customMarker2('D', Colors.purple),
      ),
      MarkerData(
        marker: Marker(
          markerId: const MarkerId('id-5'),
          position: locations[4],
        ),
        child: _customMarker('A', Colors.blue),
      ),
    ];
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            if (_customMarkers.isNotEmpty) {
              _customMarkers.removeLast();
            }
          });
        },
      ),
      body: CustomGoogleMapMarkerBuilder(
        // screenshotDelay: const Duration(seconds: 4),
        customMarkers: _customMarkers,
        builder: (BuildContext context, Set<Marker>? markers) {
          if (markers == null) {
            return const Center(child: CircularProgressIndicator());
          }
          return GoogleMap(
            initialCameraPosition: const CameraPosition(
              target: LatLng(37.42796133580664, -122.085749655962),
              zoom: 14.4746,
            ),
            markers: markers,
            onMapCreated: (GoogleMapController controller) {},
          );
        },
      ),
    );
  }

  _customMarker(String symbol, Color color) {
    return Stack(
      children: [
        Icon(
          Icons.add_location,
          color: color,
          size: 50,
        ),
        Positioned(
          left: 15,
          top: 8,
          child: Container(
            width: 20,
            height: 20,
            decoration: BoxDecoration(
                color: Colors.white, borderRadius: BorderRadius.circular(10)),
            child: Center(child: Text(symbol)),
          ),
        )
      ],
    );
  }

  _customMarker2(String symbol, Color color) {
    return Container(
      width: 30,
      height: 30,
      margin: const EdgeInsets.all(8),
      decoration: BoxDecoration(
          border: Border.all(color: color, width: 2),
          color: Colors.white,
          borderRadius: BorderRadius.circular(15),
          boxShadow: [BoxShadow(color: color, blurRadius: 6)]),
      child: Center(child: Text(symbol)),
    );
  }

  _customMarker3(String text, Color color) {
    return Container(
      margin: const EdgeInsets.all(8),
      padding: const EdgeInsets.all(8),
      decoration: BoxDecoration(
          border: Border.all(color: color, width: 2),
          color: Colors.white,
          borderRadius: BorderRadius.circular(4),
          boxShadow: [BoxShadow(color: color, blurRadius: 6)]),
      child: Center(
          child: Text(
        text,
        textAlign: TextAlign.center,
      )),
    );
  }
}

更多关于Flutter自定义地图标记插件custom_map_markers的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自定义地图标记插件custom_map_markers的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用custom_map_markers插件来自定义地图标记的一个代码示例。custom_map_markers插件允许你在Google Maps上添加自定义标记,这些标记可以是图片、图标或者其它复杂的Widget。

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

dependencies:
  flutter:
    sdk: flutter
  google_maps_flutter: ^2.0.10  # 请检查最新版本
  custom_map_markers: ^0.1.0    # 请检查最新版本

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

接下来,在你的Flutter项目中,你可以按照以下步骤使用custom_map_markers插件:

  1. 导入必要的包
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:custom_map_markers/custom_map_markers.dart';
  1. 定义自定义标记的Widget
class CustomMarker extends StatelessWidget {
  final LatLng position;

  CustomMarker({required this.position});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: Colors.blueAccent,
      ),
      child: Center(
        child: Icon(
          Icons.location_on,
          color: Colors.white,
        ),
      ),
    );
  }
}
  1. 创建地图并添加自定义标记
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Custom Map Markers Example'),
        ),
        body: MapScreen(),
      ),
    );
  }
}

class MapScreen extends StatefulWidget {
  @override
  _MapScreenState createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> {
  late GoogleMapController _controller;
  final Set<Marker> _markers = {};
  final LatLng _center = LatLng(40.7128, -74.0060); // 纽约市

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        GoogleMap(
          mapType: MapType.normal,
          initialCameraPosition: CameraPosition(
            target: _center,
            zoom: 12.0,
          ),
          markers: _markers.toSet(),
          onMapCreated: (GoogleMapController controller) {
            _controller = controller;
            _addMarkers();
          },
        ),
        // 自定义标记层(使用Stack覆盖在GoogleMap上)
        Positioned(
          top: _center.latitude * 100000 - 25, // 根据纬度简单计算Y轴位置
          left: _center.longitude * 100000 - 25, // 根据经度简单计算X轴位置
          child: Transform.translate(
            offset: Offset(
              // 这里需要更精确的计算来调整标记位置
              0, 
              0 
            ),
            child: CustomMarker(position: _center),
          ),
        ),
      ],
    );
  }

  void _addMarkers() {
    // 使用Google Maps的Marker添加默认标记(可选)
    setState(() {
      _markers.add(Marker(
        markerId: MarkerId('default_marker'),
        position: _center,
        infoWindow: InfoWindow(title: 'Default Marker', snippet: 'Default Marker Info'),
      ));
    });
  }
}

注意:由于custom_map_markers插件的API可能有所不同,且直接在Google Map Widget上覆盖自定义Widget可能涉及到复杂的坐标转换和定位调整,上面的代码示例使用了StackPositioned来简单演示如何覆盖一个自定义的Widget作为标记。在实际应用中,你可能需要更精确地计算标记的位置,或者查找是否有更高级的插件或方法来实现这一功能。

此外,custom_map_markers插件的官方文档或示例代码可能会提供更详细和精确的使用方法,建议查阅相关文档以获取最新和最佳实践。

回到顶部