-
-
Notifications
You must be signed in to change notification settings - Fork 23
Closed
Labels
bugSomething isn't workingSomething isn't working
Milestone
Description
Platforms
Web
Version of flutter-maplibre
0.3.0
Bug Description
I'm using the exact same code of the Example App but I can't pan, zoom, pitch or rotate the map. However, if I use allowInteraction: false, then I can make them all.
Steps to Reproduce
- Copy the same code of the Example App
- Try to pan, zoom, pitch or zoom.
Expected Results
I can do all the gestures that I enable in the map options.
Actual Results
I can't do any of them.
Code Sample
import 'package:flutter/material.dart';
import 'package:maplibre/maplibre.dart';
class MapScreen extends StatefulWidget {
const MapScreen({super.key});
@override
State<MapScreen> createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
late final MapController _mapController;
final GlobalKey _mapKey = GlobalKey();
final _markerPositions = [
const Geographic(lon: -10, lat: 0),
const Geographic(lon: -5, lat: 0),
const Geographic(lon: 0, lat: 0),
const Geographic(lon: 5, lat: 0),
];
Geographic? _originalPosition;
MapGestures _mapGestures = const MapGestures.all();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Interactive Widget Layer')),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(left: 16, bottom: 8),
child: Text(
'Long tap map: Create marker.\nTap marker: Show dialog.\nLong tap marker: Show popup menu.\nTap+drag marker: Move marker.',
textAlign: TextAlign.left,
),
),
Expanded(
child: MapLibreMap(
key: _mapKey,
options: MapOptions(
initZoom: 3,
initCenter: const Geographic(lon: 0, lat: 0),
gestures: _mapGestures,
),
onMapCreated: (controller) => _mapController = controller,
onEvent: (event) async {
if (event is MapEventLongClick) {
final position = event.point;
_markerPositions.add(position);
setState(() {});
}
},
children: [
WidgetLayer(
allowInteraction: false,
markers: List.generate(
_markerPositions.length,
(index) => Marker(
size: const Size.square(50),
point: _markerPositions[index],
child: GestureDetector(
onTap: () => _onTap(index),
onLongPressStart: (details) =>
_onLongPress(index, details),
onPanStart: (details) => _onPanStart(details, index),
onPanUpdate: (details) async =>
_onPanUpdate(details, index),
onPanEnd: (details) async => _onPanEnd(details, index),
child: const Icon(
Icons.location_on,
color: Colors.red,
size: 50,
),
),
alignment: Alignment.bottomCenter,
),
),
),
// display the UI widgets above the widget markers.
const MapScalebar(),
const SourceAttribution(),
const MapControlButtons(),
const MapCompass(),
],
),
),
],
),
);
}
@override
void dispose() {
super.dispose();
}
Future<Geographic> _toLngLat(Offset eventOffset) async {
final mapRenderBox =
_mapKey.currentContext?.findRenderObject() as RenderBox?;
assert(mapRenderBox != null, 'RenderBox of Map should never be null');
final mapOffset = mapRenderBox!.localToGlobal(Offset.zero);
final offset = Offset(
eventOffset.dx - mapOffset.dx,
eventOffset.dy - mapOffset.dy,
);
return _mapController.toLngLat(offset);
}
void _onLongPress(int index, LongPressStartDetails details) {
final offset = details.globalPosition;
showMenu(
context: context,
position: RelativeRect.fromLTRB(
offset.dx,
offset.dy,
MediaQuery.of(context).size.width - offset.dx,
MediaQuery.of(context).size.height - offset.dy,
),
items: [
const PopupMenuItem<void>(child: Text('Edit')),
PopupMenuItem<void>(
onTap: () async {
final isConfirmed = await _showConfirmationDialogDelete(index);
if (isConfirmed) {
_markerPositions.removeAt(index);
setState(() {});
}
},
child: const Text('Delete'),
),
],
);
}
Future<void> _onPanEnd(DragEndDetails details, int index) async {
final isAccepted = await _showConfirmationDialogMove();
if (!isAccepted) {
_markerPositions[index] = _originalPosition!;
} else {
final newPosition = await _toLngLat(details.globalPosition);
_markerPositions[index] = newPosition;
}
_originalPosition = null;
setState(() {
_mapGestures = const MapGestures.all();
});
}
void _onPanStart(DragStartDetails details, int index) {
// Keep original position in case of discarded move
_originalPosition = Geographic.from(_markerPositions[index]);
setState(() {
// Disable camera panning while a marker gets moved.
_mapGestures = const MapGestures.all(pan: false);
});
}
Future<void> _onPanUpdate(DragUpdateDetails details, int index) async {
final newPosition = await _toLngLat(details.globalPosition);
_markerPositions[index] = newPosition;
setState(() {});
}
void _onTap(int index) {
_showMarkerDetails(index);
}
Future<bool> _showConfirmationDialogDelete(int index) async {
final isConfirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text('Delete marker [$index]?'),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop(false);
},
),
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Delete'),
onPressed: () {
Navigator.of(context).pop(true);
},
),
],
),
);
return isConfirmed ?? false;
}
Future<bool> _showConfirmationDialogMove() async {
final isConfirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Accept new position?'),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Discard'),
onPressed: () {
Navigator.of(context).pop(false);
},
),
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Accept'),
onPressed: () {
Navigator.of(context).pop(true);
},
),
],
),
);
return isConfirmed ?? false;
}
Future<void> _showMarkerDetails(int index) async {
await showDialog<void>(
context: context,
builder: (context) => AlertDialog(
title: Text('Details marker with index: $index'),
content: Text('Show here the details of Marker with index $index'),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
);
return;
}
}Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Projects
Status
Done