Skip to main content
GuidesAPI ReferenceExamplesFAQ

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.

main.dart
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.

what_is_nearby_page.dart
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.

what_is_nearby_page.dart
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';
}
}
}