Flutter地图编辑插件edit_map的使用

Flutter地图编辑插件edit_map的使用

Edit Map

允许用户与各种二维形状进行交互的地图。

灵感来源于FlutterGallery 2D Transformations

请支持项目:点个❤️并收藏仓库

资源

入门指南

只需导入EditMap小部件并开始交互:

class _MyHomeView extends StatefulWidget {
  const _MyHomeView({Key? key, required this.mapImageFile}) : super(key: key);

  final File mapImageFile;

  [@override](/user/override)
  State<_MyHomeView> createState() => _MyHomeViewState();
}

class _MyHomeViewState extends State<_MyHomeView> {
  bool isDraggableDeskShown = false;
  List<DeskPayload> desks = [];
  DeskPayload? lastModifiedObject;

  int index = 0;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          InkWell(
            onTap: () {
              setState(() {
                if (lastModifiedObject != null) {
                  desks = desks.toList()..add(lastModifiedObject!);
                  lastModifiedObject = null;
                }
                isDraggableDeskShown = false;
              });
            },
            child: const Center(
              child: Text('Save'),
            ),
          ),
          InkWell(
            onTap: () {
              setState(() {
                isDraggableDeskShown = true;
              });
            },
            child: const AspectRatio(
              aspectRatio: 1,
              child: Center(
                child: Text(
                  '+',
                  style: TextStyle(color: Colors.white, fontSize: 34),
                ),
              ),
            ),
          )
        ],
      ),
      body: SizedBox.expand(
        child: EditMap(
          isEditMode: true,
          mapImage: widget.mapImageFile,
          deskParamsList: desks,
          selectedDesk: isDraggableDeskShown
              ? DeskPayload(deskParams: const DeskParams(id: '1'))
              : null,
          onDeskMoved: (Offset deskPosition) {
            if (kDebugMode) {
              print(
                  '---desk moved---\nx:${deskPosition.dx}\ny:${deskPosition.dy}');
            }
            WidgetsBinding.instance.addPostFrameCallback((_) async {
              setState(() {
                lastModifiedObject = DeskPayload(
                  deskParams: DeskParams(
                    id: (++index).toString(),
                    area: Area(position: deskPosition),
                  ),
                );
              });
            });
          },
        ),
      ),
    );
  }
}

示例代码

以下是完整的示例代码,展示了如何在应用中使用edit_map插件:

import 'dart:io';

import 'package:dio/dio.dart';
import 'package:edit_map/edit_map.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.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: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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> {
  Future<File> _loadImage() async {
    Response response = await Dio().get(
      'https://firebasestorage.googleapis.com/v0/b/workplacer-1deda.appspot.com/o/data%2Fuser%2F0%2Fhash.apps.workplacer%2Fcache%2Fimage_picker4792814428577454194.png?alt=media&token=aca939cc-28fa-4f9e-abfb-be3bd3e2a933',
      options: Options(responseType: ResponseType.bytes),
    );
    final tempDirectory = await getTemporaryDirectory();
    final file = File('${tempDirectory.path}/office-plan.jgp');
    final raf = file.openSync(mode: FileMode.write);
    raf.writeFromSync(response.data);
    await raf.close();
    return Future.value(file);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _loadImage(),
      builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
        if (snapshot.data != null && snapshot.hasData) {
          return _MyHomeView(mapImageFile: snapshot.data!);
        }
        return const Center(
          child: CircularProgressIndicator(
              // valueColor: AlwaysStoppedAnimation<Color>(),
              ),
        );
      },
    );
  }
}

class _MyHomeView extends StatefulWidget {
  const _MyHomeView({Key? key, required this.mapImageFile}) : super(key: key);

  final File mapImageFile;

  [@override](/user/override)
  State<_MyHomeView> createState() => _MyHomeViewState();
}

class _MyHomeViewState extends State<_MyHomeView> {
  bool isDraggableDeskShown = false;
  List<DeskPayload> desks = [];
  DeskPayload? lastModifiedObject;

  int index = 0;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: lastModifiedObject != null
            ? Slider.adaptive(
                value: lastModifiedObject!.area.rotation / 1500,
                activeColor: Colors.black,
                onChanged: (double value) {
                  // TODO 修复旋转后的点击问题
                  final angle = double.parse(value.toStringAsFixed(2)) * 1500;
                  if (angle != lastModifiedObject!.area.rotation) {
                    lastModifiedObject =
                        lastModifiedObject!.copyWith(rotation: angle);
                    setState(() {});
                  }
                },
                max: 0.24,
              )
            : null,
        actions: [
          InkWell(
            onTap: () {
              if (lastModifiedObject != null) {
                desks = desks.toList()..add(lastModifiedObject!);
                lastModifiedObject = null;
                setState(() {});
              }
            },
            child: const Center(
              child: Text('Save'),
            ),
          ),
          InkWell(
            onTap: () {
              lastModifiedObject =
                  DeskPayload(deskParams: DeskParams(id: (index++).toString()));
              setState(() {});
            },
            child: const AspectRatio(
              aspectRatio: 1,
              child: Center(
                child: Text(
                  '+',
                  style: TextStyle(color: Colors.white, fontSize: 34),
                ),
              ),
            ),
          )
        ],
      ),
      body: SizedBox.expand(
        child: EditMap(
          isEditMode: true,
          mapImage: widget.mapImageFile,
          deskParamsList: desks,
          selectedDesk: lastModifiedObject,
          onDeskMoved: (Offset deskPosition) {
            if (kDebugMode) {
              print(
                  '---desk moved---\nx:${deskPosition.dx}\ny:${deskPosition.dy}');
            }
            WidgetsBinding.instance.addPostFrameCallback((_) async {
              setState(() {
                lastModifiedObject =
                    lastModifiedObject?.copyWith(position: deskPosition);
              });
            });
          },
        ),
      ),
    );
  }
}

更多关于Flutter地图编辑插件edit_map的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

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


当然,以下是如何在Flutter项目中使用edit_map插件的一个基本示例。请注意,edit_map插件并不是Flutter官方或广泛认可的插件,因此具体API和用法可能会有所不同。假设你有一个类似功能的插件或自定义实现,以下代码展示了如何集成和使用一个地图编辑功能。

首先,确保你已经在pubspec.yaml文件中添加了必要的依赖项。由于edit_map不是公认的插件名,这里假设我们使用flutter_map作为基础地图插件,并自定义编辑功能:

dependencies:
  flutter:
    sdk: flutter
  flutter_map: ^0.14.0  # 使用最新版本
  latlong2: ^0.8.0      # flutter_map的依赖

然后,运行flutter pub get来获取依赖项。

接下来,创建一个Flutter页面来展示和编辑地图。这里我们将使用flutter_map来显示地图,并通过一些交互组件来实现编辑功能。为了简化,我们假设编辑功能包括添加和移动标记(markers)。

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:positioned_tap_detector/positioned_tap_detector.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MapPage(),
    );
  }
}

class MapPage extends StatefulWidget {
  @override
  _MapPageState createState() => _MapPageState();
}

class _MapPageState extends State<MapPage> {
  final MapController _mapController = MapController();
  List<Marker> _markers = [];
  LatLng? _tappedPosition;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Map Editor'),
      ),
      body: Stack(
        children: [
          FlutterMap(
            mapController: _mapController,
            options: MapOptions(
              center: LatLng(0, 0),
              zoom: 2.0,
            ),
            layers: [
              TileLayerOptions(
                urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
                subdomains: ['a', 'b', 'c'],
              ),
              MarkerLayerOptions(markers: _markers),
            ],
          ),
          PositionedTapDetector(
            onTapDown: (details) {
              final RenderBox? box = context.findRenderObject() as RenderBox?;
              final Offset tapPosition = details.globalPosition;
              final Offset localPosition = box!.globalToLocal(tapPosition);
              final point = _mapController.project(tapPosition);
              setState(() {
                _tappedPosition = LatLng(point.y, point.x);
                _markers.add(
                  Marker(
                    width: 80.0,
                    height: 80.0,
                    point: _tappedPosition!,
                    builder: (ctx) => Container(
                      child: Icon(
                        Icons.location_on,
                        color: Colors.red,
                        size: 40,
                      ),
                    ),
                  ),
                );
              });
            },
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // Reset markers for simplicity in this demo
          setState(() {
            _markers = [];
          });
        },
        tooltip: 'Reset Markers',
        child: Icon(Icons.clear),
      ),
    );
  }
}

在这个示例中:

  1. 我们使用了flutter_map来显示地图。
  2. PositionedTapDetector用于检测地图上的点击位置,并将点击位置转换为地图坐标(LatLng)。
  3. 每次点击地图时,都会在点击位置添加一个标记。
  4. 浮动操作按钮(FAB)用于重置所有标记。

请注意,这只是一个基础示例,实际的地图编辑功能可能需要更多的定制,例如拖动标记、保存和加载编辑内容等。你可能需要根据具体需求进一步扩展这个示例。

回到顶部