尝试在谷歌地图上显示自定义标记时,BitmapDescriptor.fromBytes() 不起作用
Posted
技术标签:
【中文标题】尝试在谷歌地图上显示自定义标记时,BitmapDescriptor.fromBytes() 不起作用【英文标题】:BitmapDescriptor.fromBytes() is not working when trying to show custom marker on google maps 【发布时间】:2020-09-06 21:53:24 【问题描述】:我正在尝试将自定义图像显示为谷歌地图上的标记。问题是 BitmapDescriptor.fromAssetImage() 工作正常,但 BitmapDescriptor.fromBytes() 不工作。由于我必须进一步使用画布,我需要使用 BitmapDescriptor.fromBytes()。任何帮助表示赞赏。下面是完整的代码。
class AqiMapPage extends StatefulWidget
@override
_AqiMapPageState createState() => _AqiMapPageState();
Future<BitmapDescriptor> getCustomMapMarker(int aqi) async
Levels levels = AqiCnAqiRange.getAqiLevel(aqi);
// this is working
/* return await BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 2.5),
'assets/markers/$levels.markerIcon');*/
// this is not working
return await _getAssetIcon(_context, 'assets/markers/$levels.markerIcon');
Future<BitmapDescriptor> _getAssetIcon(BuildContext context, String imageUrl) async
final Completer<BitmapDescriptor> bitmapIcon =
Completer<BitmapDescriptor>();
final ImageConfiguration config = createLocalImageConfiguration(context);
AssetImage(imageUrl)
.resolve(config)
.addListener(ImageStreamListener((ImageInfo image, bool sync) async
final ByteData bytes =
await image.image.toByteData(format: ImageByteFormat.png);
final BitmapDescriptor bitmap =
BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());
bitmapIcon.complete(bitmap);
));
return await bitmapIcon.future;
Future<Set<Marker>> getMarkerList(List<MapData> mapData) async
Set<Marker> markerList = Set();
mapData.forEach((element) async
try
BitmapDescriptor bitmapDescriptor =
await getCustomMapMarker(int.parse(element.aqi));
Marker marker = new Marker(
markerId: MarkerId(element.aqi),
position: LatLng(element.lat, element.lon),
icon: bitmapDescriptor,
);
markerList.add(marker);
catch (e)
print(e.toString());
);
return markerList;
Completer<GoogleMapController> _controller;
BuildContext _context;
final _scaffoldKey = GlobalKey<ScaffoldState>();
class _AqiMapPageState extends State<AqiMapPage>
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
new GlobalKey<RefreshIndicatorState>();
AqiCnMapBloc _bloc;
@override
void initState()
super.initState();
_controller = Completer();
_bloc = AqiCnMapBloc();
_bloc.getAqiCnMap(false);
@override
Widget build(BuildContext context)
_context = context;
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text(AppLocalizations.of(context)
.getString(AppStringKeys.AQI_MAP_PAGE_KEY)),
centerTitle: true,
),
backgroundColor: HexColor.fromHex(AppColors.scaffoldBackgroundColor),
body: new RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: () => _bloc.getAqiCnMap(true),
child: StreamBuilder<Response<AqiCnMapApiResponse>>(
stream: _bloc.aqiCnMapStream,
builder: (context, snapshot)
if (snapshot.hasData)
switch (snapshot.data.status)
case Status.LOADING:
return Loading(loadingKey: snapshot.data.message);
break;
case Status.SUCCESS:
return AqiMapData(mapData: snapshot.data.data);
break;
case Status.ERROR:
return Error(
error: snapshot.data.message,
onRetryPressed: () => _bloc.getAqiCnMap(false),
);
break;
return Container();
,
),
),
);
class AqiMapData extends StatelessWidget
final AqiCnMapApiResponse mapData;
const AqiMapData(Key key, this.mapData) : super(key: key);
@override
Widget build(BuildContext context)
return FutureBuilder<Set<Marker>>(
future: getMarkerList(mapData.mapData),
builder: (BuildContext context, AsyncSnapshot<Set<Marker>> snapshot)
if (!snapshot.hasData)
// while data is loading:
return LoadingWithoutText();
else
// data loaded:
return GoogleMap(
mapType: MapType.hybrid,
myLocationEnabled: true,
// fixme - fix lat lng
initialCameraPosition:
CameraPosition(target: LatLng(25.6185024, 85.0726964), zoom: 3),
markers: snapshot.data,
onMapCreated: (GoogleMapController controller)
_controller.complete(controller);
,
);
,
);
【问题讨论】:
【参考方案1】:我找到了解决办法。虽然我不确定上面的代码有什么问题。但这似乎是某种同步或渲染问题。并且使用 setState() 我可以使用 BitmapDescriptor.fromBytes()。下面是我的代码。
class AqiMapPage extends StatefulWidget
@override
_AqiMapPageState createState() => _AqiMapPageState();
final _scaffoldKey = GlobalKey<ScaffoldState>();
class _AqiMapPageState extends State<AqiMapPage>
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
new GlobalKey<RefreshIndicatorState>();
AqiCnMapBloc _bloc;
@override
void initState()
super.initState();
_bloc = AqiCnMapBloc();
_bloc.getAqiCnMap(false);
@override
Widget build(BuildContext context)
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text(AppLocalizations.of(context)
.getString(AppStringKeys.AQI_MAP_PAGE_KEY)),
centerTitle: true,
),
backgroundColor: HexColor.fromHex(AppColors.scaffoldBackgroundColor),
body: new RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: () => _bloc.getAqiCnMap(true),
child: StreamBuilder<Response<AqiCnMapApiResponse>>(
stream: _bloc.aqiCnMapStream,
builder: (context, snapshot)
if (snapshot.hasData)
switch (snapshot.data.status)
case Status.LOADING:
return Loading(loadingKey: snapshot.data.message);
break;
case Status.SUCCESS:
return AqiMapData(mapData: snapshot.data.data);
break;
case Status.ERROR:
return Error(
error: snapshot.data.message,
onRetryPressed: () => _bloc.getAqiCnMap(false),
);
break;
return Container();
,
),
),
);
class AqiMapData extends StatefulWidget
final AqiCnMapApiResponse mapData;
const AqiMapData(Key key, this.mapData) : super(key: key);
@override
_AqiMapDataState createState() => _AqiMapDataState(mapData);
class _AqiMapDataState extends State<AqiMapData>
final AqiCnMapApiResponse mapData;
_AqiMapDataState(this.mapData);
Set<Marker> _markers = Set();
Completer<GoogleMapController> _controller = Completer();
static Future<Uint8List> getBytesFromAsset(String path, int width) async
ByteData data = await rootBundle.load(path);
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),
targetWidth: width);
ui.FrameInfo fi = await codec.getNextFrame();
return (await fi.image.toByteData(format: ImageByteFormat.png))
.buffer
.asUint8List();
populateMarkers()
mapData.mapData.forEach((element) async
try
final MarkerId markerId = MarkerId(element.uid.toString());
Levels levels = AqiCnAqiRange.getAqiLevel(int.parse(element.aqi));
final Uint8List markerIcon = await getBytesFromAsset('assets/markers/$levels.markerIcon', 100);
// creating a new MARKER
final Marker marker = new Marker(
icon: BitmapDescriptor.fromBytes(markerIcon),
markerId: markerId,
position: LatLng(element.lat, element.lon),
infoWindow: InfoWindow(
title: element.station.name, snippet: element.station.time),
);
// the solution
setState(()
// adding a new marker to map
_markers.add(marker);
);
catch (e)
print(e.toString());
);
@override
void initState()
super.initState();
populateMarkers();
@override
Widget build(BuildContext context)
return GoogleMap(
mapType: MapType.hybrid,
myLocationEnabled: true,
// fixme - fix lat lng
initialCameraPosition:
CameraPosition(target: LatLng(25.6185024, 85.0726964), zoom: 3),
markers: _markers,
onMapCreated: (GoogleMapController controller)
_controller.complete(controller);
,
);
【讨论】:
以上是关于尝试在谷歌地图上显示自定义标记时,BitmapDescriptor.fromBytes() 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
在谷歌地图自定义标记未显示在三星 S8 或 Android 的相同版本 7.0