Skip to content

Instantly share code, notes, and snippets.

@hleinone
Last active June 29, 2022 12:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hleinone/59fe6276fb56850e42c83e0c611f551f to your computer and use it in GitHub Desktop.
Save hleinone/59fe6276fb56850e42c83e0c611f551f to your computer and use it in GitHub Desktop.
Google Maps for Flutter Customizable Buttons
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
/// A button resembling the built-in 'compass' indicator from Google Maps SDK.
/// This supports both light and dark themes. Requires material,
/// google_maps_flutter and flutter_svg.
@immutable
class Compass extends StatelessWidget {
const Compass({
Key? key,
Completer<GoogleMapController>? controller,
required this.cameraPosition,
this.onPressed,
this.tooltip,
}) : assert(
controller != null || onPressed != null,
'Either controller or onPressed must be provided',
),
_controller = controller,
super(key: key);
final Completer<GoogleMapController>? _controller;
final Stream<CameraPosition> cameraPosition;
final void Function()? onPressed;
final String? tooltip;
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: cameraPosition,
builder: (context, AsyncSnapshot<CameraPosition> cameraPosition) {
final data = cameraPosition.data;
final isStraight = data?.isStraight ?? true;
final tiltRadians = data?.tiltRadians ?? 0;
final bearingRadians = data?.bearingRadians ?? 0;
final button = AnimatedOpacity(
duration: isStraight
? const Duration(seconds: 2)
: kThemeChangeDuration,
opacity: data?.isStraight ?? true ? 0 : 1,
curve: const Interval(0.8, 1),
child: OutlinedButton(
onPressed: isStraight
? () {}
: onPressed ??
() async {
final controller = await _controller!.future;
final center = data?.target ?? await () async {
final visibleRegion = await controller.getVisibleRegion();
final northeastScreen = await controller
.getScreenCoordinate(visibleRegion.northeast);
final southwestScreen = await controller
.getScreenCoordinate(visibleRegion.southwest);
final centerScreen = ScreenCoordinate(
x: ((northeastScreen.x + southwestScreen.x) / 2)
.round(),
y: ((northeastScreen.y + southwestScreen.y) / 2)
.round(),
);
return await controller.getLatLng(centerScreen);
}();
final zoom = data?.zoom ?? await controller.getZoomLevel();
controller.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
tilt: 0,
bearing: 0,
target: center,
zoom: zoom,
),
),
);
},
style: OutlinedButton.styleFrom(
elevation: 0,
backgroundColor:
Theme.of(context).colorScheme.surface.withAlpha(191),
padding: const EdgeInsets.all(0),
fixedSize: const Size(36, 36),
minimumSize: const Size(36, 36),
primary: Theme.of(context).colorScheme.onSurface.withAlpha(191),
shape: const CircleBorder(),
side: BorderSide(
color: Theme.of(context).colorScheme.onSurface.withAlpha(64),
width: 1,
),
),
child: Padding(
padding: const EdgeInsets.all(6),
child: Transform(
transform: Matrix4.rotationX(tiltRadians),
alignment: Alignment.center,
transformHitTests: true,
child: Transform.rotate(
transformHitTests: true,
angle: bearingRadians,
child: SvgPicture.asset('assets/vector/compass_needle.svg'),
),
),
),
),
);
return IgnorePointer(
ignoring: isStraight,
child: tooltip != null ?
Tooltip(message: tooltip, child: button) :
button,
);
},
);
}
}
extension CameraPositionExtension on CameraPosition {
bool get isStraight => bearing == 0 && tilt == 0;
double get bearingRadians => bearing * -pi / 180;
double get tiltRadians => tilt * pi / 180;
}
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
/// A button resembling the built-in 'my location' button from Google Maps SDK.
/// This supports both light and dark themes. Requires material,
/// google_maps_flutter and location.
@immutable
class MyLocationButton extends StatelessWidget {
const MyLocationButton({
Key? key,
Completer<GoogleMapController>? controller,
Location? location,
this.onPressed,
this.tooltip,
}) : assert(
(controller != null && location != null) || onPressed != null,
'Either controller and location or onPressed must be provided',
),
_controller = controller,
_location = location,
super(key: key);
final Completer<GoogleMapController>? _controller;
final Location? _location;
final void Function()? onPressed;
final String? tooltip;
@override
Widget build(BuildContext context) {
final button = OutlinedButton(
onPressed: onPressed ??
() async {
final controller = await _controller!.future;
final location = await _location!.getLocation();
final latitude = location.latitude;
final longitude = location.longitude;
if (latitude == null || longitude == null) return;
controller.animateCamera(
CameraUpdate.newLatLng(LatLng(latitude, longitude)),
);
},
style: OutlinedButton.styleFrom(
elevation: 0,
backgroundColor:
Theme.of(context).colorScheme.surface.withAlpha(191),
padding: const EdgeInsets.all(0),
fixedSize: const Size(40, 40),
minimumSize: const Size(40, 40),
primary: Theme.of(context).colorScheme.onSurface.withAlpha(191),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero,
),
side: BorderSide(
color: Theme.of(context).colorScheme.onSurface.withAlpha(64),
width: 1,
),
),
child: const Icon(Icons.my_location),
);
if (tooltip != null) {
return Tooltip(message: tooltip, child: button);
}
return button;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment