blob: 2c6c725a4fa590b2fb97d5465fcc5aa644332f8d [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
import 'example_google_map.dart';
import 'page.dart';
class PlaceMarkerPage extends GoogleMapExampleAppPage {
const PlaceMarkerPage({Key? key})
: super(const Icon(Icons.place), 'Place marker', key: key);
@override
Widget build(BuildContext context) {
return const PlaceMarkerBody();
}
}
class PlaceMarkerBody extends StatefulWidget {
const PlaceMarkerBody({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => PlaceMarkerBodyState();
}
typedef MarkerUpdateAction = Marker Function(Marker marker);
class PlaceMarkerBodyState extends State<PlaceMarkerBody> {
PlaceMarkerBodyState();
static const LatLng center = LatLng(-33.86711, 151.1947171);
ExampleGoogleMapController? controller;
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
MarkerId? selectedMarker;
int _markerIdCounter = 1;
LatLng? markerPosition;
// ignore: use_setters_to_change_properties
void _onMapCreated(ExampleGoogleMapController controller) {
this.controller = controller;
}
@override
void dispose() {
super.dispose();
}
void _onMarkerTapped(MarkerId markerId) {
final Marker? tappedMarker = markers[markerId];
if (tappedMarker != null) {
setState(() {
final MarkerId? previousMarkerId = selectedMarker;
if (previousMarkerId != null && markers.containsKey(previousMarkerId)) {
final Marker resetOld = markers[previousMarkerId]!
.copyWith(iconParam: BitmapDescriptor.defaultMarker);
markers[previousMarkerId] = resetOld;
}
selectedMarker = markerId;
final Marker newMarker = tappedMarker.copyWith(
iconParam: BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueGreen,
),
);
markers[markerId] = newMarker;
markerPosition = null;
});
}
}
Future<void> _onMarkerDrag(MarkerId markerId, LatLng newPosition) async {
setState(() {
markerPosition = newPosition;
});
}
Future<void> _onMarkerDragEnd(MarkerId markerId, LatLng newPosition) async {
final Marker? tappedMarker = markers[markerId];
if (tappedMarker != null) {
setState(() {
markerPosition = null;
});
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
actions: <Widget>[
TextButton(
child: const Text('OK'),
onPressed: () => Navigator.of(context).pop(),
)
],
content: Padding(
padding: const EdgeInsets.symmetric(vertical: 66),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Old position: ${tappedMarker.position}'),
Text('New position: $newPosition'),
],
)));
});
}
}
void _add() {
final int markerCount = markers.length;
if (markerCount == 12) {
return;
}
final String markerIdVal = 'marker_id_$_markerIdCounter';
_markerIdCounter++;
final MarkerId markerId = MarkerId(markerIdVal);
final Marker marker = Marker(
markerId: markerId,
position: LatLng(
center.latitude + sin(_markerIdCounter * pi / 6.0) / 20.0,
center.longitude + cos(_markerIdCounter * pi / 6.0) / 20.0,
),
infoWindow: InfoWindow(title: markerIdVal, snippet: '*'),
onTap: () => _onMarkerTapped(markerId),
onDragEnd: (LatLng position) => _onMarkerDragEnd(markerId, position),
onDrag: (LatLng position) => _onMarkerDrag(markerId, position),
);
setState(() {
markers[markerId] = marker;
});
}
void _remove(MarkerId markerId) {
setState(() {
if (markers.containsKey(markerId)) {
markers.remove(markerId);
}
});
}
void _changePosition(MarkerId markerId) {
final Marker marker = markers[markerId]!;
final LatLng current = marker.position;
final Offset offset = Offset(
center.latitude - current.latitude,
center.longitude - current.longitude,
);
setState(() {
markers[markerId] = marker.copyWith(
positionParam: LatLng(
center.latitude + offset.dy,
center.longitude + offset.dx,
),
);
});
}
void _changeAnchor(MarkerId markerId) {
final Marker marker = markers[markerId]!;
final Offset currentAnchor = marker.anchor;
final Offset newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx);
setState(() {
markers[markerId] = marker.copyWith(
anchorParam: newAnchor,
);
});
}
Future<void> _changeInfoAnchor(MarkerId markerId) async {
final Marker marker = markers[markerId]!;
final Offset currentAnchor = marker.infoWindow.anchor;
final Offset newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx);
setState(() {
markers[markerId] = marker.copyWith(
infoWindowParam: marker.infoWindow.copyWith(
anchorParam: newAnchor,
),
);
});
}
Future<void> _toggleDraggable(MarkerId markerId) async {
final Marker marker = markers[markerId]!;
setState(() {
markers[markerId] = marker.copyWith(
draggableParam: !marker.draggable,
);
});
}
Future<void> _toggleFlat(MarkerId markerId) async {
final Marker marker = markers[markerId]!;
setState(() {
markers[markerId] = marker.copyWith(
flatParam: !marker.flat,
);
});
}
Future<void> _changeInfo(MarkerId markerId) async {
final Marker marker = markers[markerId]!;
final String newSnippet = '${marker.infoWindow.snippet!}*';
setState(() {
markers[markerId] = marker.copyWith(
infoWindowParam: marker.infoWindow.copyWith(
snippetParam: newSnippet,
),
);
});
}
Future<void> _changeAlpha(MarkerId markerId) async {
final Marker marker = markers[markerId]!;
final double current = marker.alpha;
setState(() {
markers[markerId] = marker.copyWith(
alphaParam: current < 0.1 ? 1.0 : current * 0.75,
);
});
}
Future<void> _changeRotation(MarkerId markerId) async {
final Marker marker = markers[markerId]!;
final double current = marker.rotation;
setState(() {
markers[markerId] = marker.copyWith(
rotationParam: current == 330.0 ? 0.0 : current + 30.0,
);
});
}
Future<void> _toggleVisible(MarkerId markerId) async {
final Marker marker = markers[markerId]!;
setState(() {
markers[markerId] = marker.copyWith(
visibleParam: !marker.visible,
);
});
}
Future<void> _changeZIndex(MarkerId markerId) async {
final Marker marker = markers[markerId]!;
final double current = marker.zIndex;
setState(() {
markers[markerId] = marker.copyWith(
zIndexParam: current == 12.0 ? 0.0 : current + 1.0,
);
});
}
void _setMarkerIcon(MarkerId markerId, BitmapDescriptor assetIcon) {
final Marker marker = markers[markerId]!;
setState(() {
markers[markerId] = marker.copyWith(
iconParam: assetIcon,
);
});
}
Future<BitmapDescriptor> _getAssetIcon(BuildContext context) async {
final Completer<BitmapDescriptor> bitmapIcon =
Completer<BitmapDescriptor>();
final ImageConfiguration config = createLocalImageConfiguration(context);
const AssetImage('assets/red_square.png')
.resolve(config)
.addListener(ImageStreamListener((ImageInfo image, bool sync) async {
final ByteData? bytes =
await image.image.toByteData(format: ImageByteFormat.png);
if (bytes == null) {
bitmapIcon.completeError(Exception('Unable to encode icon'));
return;
}
final BitmapDescriptor bitmap =
BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());
bitmapIcon.complete(bitmap);
}));
return bitmapIcon.future;
}
@override
Widget build(BuildContext context) {
final MarkerId? selectedId = selectedMarker;
return Stack(children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: ExampleGoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: const CameraPosition(
target: LatLng(-33.852, 151.211),
zoom: 11.0,
),
markers: Set<Marker>.of(markers.values),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
TextButton(
onPressed: _add,
child: const Text('Add'),
),
TextButton(
onPressed:
selectedId == null ? null : () => _remove(selectedId),
child: const Text('Remove'),
),
],
),
Wrap(
alignment: WrapAlignment.spaceEvenly,
children: <Widget>[
TextButton(
onPressed:
selectedId == null ? null : () => _changeInfo(selectedId),
child: const Text('change info'),
),
TextButton(
onPressed: selectedId == null
? null
: () => _changeInfoAnchor(selectedId),
child: const Text('change info anchor'),
),
TextButton(
onPressed:
selectedId == null ? null : () => _changeAlpha(selectedId),
child: const Text('change alpha'),
),
TextButton(
onPressed:
selectedId == null ? null : () => _changeAnchor(selectedId),
child: const Text('change anchor'),
),
TextButton(
onPressed: selectedId == null
? null
: () => _toggleDraggable(selectedId),
child: const Text('toggle draggable'),
),
TextButton(
onPressed:
selectedId == null ? null : () => _toggleFlat(selectedId),
child: const Text('toggle flat'),
),
TextButton(
onPressed: selectedId == null
? null
: () => _changePosition(selectedId),
child: const Text('change position'),
),
TextButton(
onPressed: selectedId == null
? null
: () => _changeRotation(selectedId),
child: const Text('change rotation'),
),
TextButton(
onPressed: selectedId == null
? null
: () => _toggleVisible(selectedId),
child: const Text('toggle visible'),
),
TextButton(
onPressed:
selectedId == null ? null : () => _changeZIndex(selectedId),
child: const Text('change zIndex'),
),
TextButton(
onPressed: selectedId == null
? null
: () {
_getAssetIcon(context).then(
(BitmapDescriptor icon) {
_setMarkerIcon(selectedId, icon);
},
);
},
child: const Text('set marker icon'),
),
],
),
],
),
Visibility(
visible: markerPosition != null,
child: Container(
color: Colors.white70,
height: 30,
padding: const EdgeInsets.only(left: 12, right: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
if (markerPosition == null)
Container()
else
Expanded(child: Text('lat: ${markerPosition!.latitude}')),
if (markerPosition == null)
Container()
else
Expanded(child: Text('lng: ${markerPosition!.longitude}')),
],
),
),
),
]);
}
}