What Is Nearby
This example demonstrates how to create a Flutter app that shows nearby landmarks based on the user’s current position using the Maps SDK for Flutter.
How It Works
This example app demonstrates the following features:
- Obtain location permissions and show a map centered on the user’s location.
- Display nearby landmarks as a list.
- Allow navigation to a detail page displaying information about nearby landmarks.
![]() | ![]() |
---|---|
Current position available | Nearby locations |
Map Display and Permissions
The map is displayed and initialized within the MyHomePage widget, which also handles location permissions for Android and iOS. This widget handles the UI, setting up the map and app bar, and uses permission_handler for requesting location permissions.
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late GemMapController _mapController;
PermissionStatus _locationPermissionStatus = PermissionStatus.denied;
bool _hasLiveDataSource = false;
void dispose() {
GemKit.release();
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepPurple[900],
title: const Text('What\'s Nearby', style: TextStyle(color: Colors.white)),
actions: [
IconButton(
onPressed: () => _onWhatIsNearbyButtonPressed(context),
icon: const Icon(Icons.question_mark, color: Colors.white),
),
],
),
body: GemMap(
key: ValueKey("GemMap"),
onMapCreated: _onMapCreated,
appAuthorization: projectApiToken,
),
);
}
Fetching Nearby Locations
The WhatIsNearbyPage widget displays a list of nearby landmarks based on the user’s current position. This code searches for nearby landmarks, displaying the results in a ListView.
class WhatIsNearbyPage extends StatefulWidget {
final Coordinates position;
const WhatIsNearbyPage({super.key, required this.position});
State<WhatIsNearbyPage> createState() => _WhatIsNearbyPageState();
}
class _WhatIsNearbyPageState extends State<WhatIsNearbyPage> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: true,
foregroundColor: Colors.white,
title: const Text(
"What's Nearby",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.deepPurple[900],
),
body: FutureBuilder(
future: _getNearbyLocations(),
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.data == null) {
return const Center(child: CircularProgressIndicator());
}
return ListView.separated(
itemBuilder: (contex, index) {
return NearbyItem(
landmark: snapshot.data!.elementAt(index),
currentPosition: widget.position,
);
},
separatorBuilder:
(context, index) => const Divider(indent: 0, height: 0),
itemCount: snapshot.data!.length,
);
},
),
);
}
Future<List<Landmark>?> _getNearbyLocations() async {
// Add all categories to SearchPreferences
final preferences = SearchPreferences(searchAddresses: false);
final genericCategories = GenericCategories.categories;
for (final category in genericCategories) {
preferences.landmarks.addStoreCategoryId(
category.landmarkStoreId,
category.id,
);
}
final completer = Completer<List<Landmark>?>();
// Perform search around position with current position and all categories
SearchService.searchAroundPosition(
preferences: preferences,
widget.position,
(err, result) {
completer.complete(result);
},
);
return completer.future;
}
}
Displaying Landmark Information
Each nearby landmark is displayed in a list tile showing the name and distance from the current position. This component formats and displays the name and distance of each landmark.
class NearbyItem extends StatefulWidget {
final Landmark landmark;
final Coordinates currentPosition;
const NearbyItem({
super.key,
required this.landmark,
required this.currentPosition,
});
State<NearbyItem> createState() => _NearbyItemState();
}
class _NearbyItemState extends State<NearbyItem> {
Widget build(BuildContext context) {
return ListTile(
title: Text(
widget.landmark.categories.first.name,
overflow: TextOverflow.fade,
style: const TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w400,
),
maxLines: 2,
),
leading: widget.landmark.img.isValid
? Image.memory(widget.landmark.img.getRenderableImageBytes(size: Size(128, 128))!)
: SizedBox(),
trailing: Text(
_convertDistance(
widget.landmark.coordinates.distance(widget.currentPosition).toInt(),
),
overflow: TextOverflow.fade,
style: const TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
);
}
String _convertDistance(int meters) {
if (meters >= 1000) {
double kilometers = meters / 1000;
return '${kilometers.toStringAsFixed(1)} km';
} else {
return '${meters.toString()} m';
}
}
}
Flutter Examples
Maps SDK for Flutter Examples can be downloaded or cloned with Git.