Reputation: 1693
I'm trying to add a google map widget with custom icons on the screen.
For that reason, I need to use the FutureBuilder
to get the icons BitmapDescriptor.fromAssetImage
before I try to render the map.
This method is an async one so I have thrown it into the FutureBuilder so the entire widget waits until all my icons are allocated.
The app works, but the problem is that it has this quick but very noticeable screen flick, which makes the area black. I have a progress indicator but it does not matter, the black screen always shows up.
@override
Widget build(BuildContext context) {
return Consumer <RestaurantsData>(
builder: (context, _restaurantsData, __) => FutureBuilder<bool>(
future: _prepareWidget(),
builder: (BuildContext buildContext, AsyncSnapshot<bool> snapshot) {
if (snapshot.connectionState == ConnectionState.done
&& snapshot.data
&& snapshot.hasData) {
return googleMap(_restaurantsData);
}
logger.d("Map widget still processing");
return Center(
// Display Progress Indicator
child: CircularProgressIndicator(
backgroundColor: Colors.white,
),
);
})
);
}
Widget googleMap(RestaurantsData _restaurantsData){
return Container(
child: GoogleMap(
mapType: MapType.normal,
myLocationEnabled: true,
myLocationButtonEnabled: true,
mapToolbarEnabled: false,
zoomGesturesEnabled: true,
rotateGesturesEnabled: true,
initialCameraPosition: CameraPosition(
target: _defaultLatLng,
zoom: _defaultZoom
),
onMapCreated: (GoogleMapController controller) {
_controller = controller;
},
onTap: (latLng) {
if (bottomSheetCtrl != null) {
bottomSheetCtrl.close();
bottomSheetCtrl = null;
}
},
markers: createRestaurantMarkers(_restaurantsData),
gestureRecognizers: _gestureRecognizers
)
);
}
Set<Marker> createRestaurantMarkers(RestaurantsData restaurantsData) {
return restaurantsData.getRestaurants()
.map((item) =>
Marker(
position: item.latLng,
markerId: MarkerId("${item.id}|${item.name}"),
icon: getIconFor(item),
onTap: () {
logger.i("Marker clicked: ${item.id}, ${item.name}");
showRestaurantDetails(context, item);
restaurantsData.selectOne(item);
}
))
.toSet();
}
The prepare widget call is as follows:
Future<bool> _prepareWidget() async {
_markerIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 2.5),
marker
);
_selectedMarkerIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 2.5),
markerSelected
);
_disabledMarkerIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 2.5),
disabledMarker
);
_disabledSelectedMarkerIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 2.5),
disabledMarkerSelected
);
return Future.value(_markerIcon != null
&& _selectedMarkerIcon != null
&& _disabledMarkerIcon != null
&& _disabledSelectedMarkerIcon != null
);
}
I have 4 icons that are always static and available from the start of the app.
Any ideas on how to fix this? I'm fairly new to flutter so this issue maybe because of something that I'm doing wrong.
Upvotes: 2
Views: 2090
Reputation: 1693
I fixed the flickering by building the Future using FuturBuilder and passing it as a Provider in an ancestor widget. It's build before all main widgets and only once.
In a parent widget:
return MultiProvider(
providers: [
FutureProvider<MapMarkerProvider>(
lazy: false,
create: (_) async => MapMarkerProvider().loadMarkers() //<- Async Action loading icons.
),
],
child: Scaffold(
appBar: new EmptyAppBar(),
body: Container(
....
)
)
);
}
Upvotes: 3