Android 试图在google地图上显示自定义标记时,BitmapDescriptor.fromBytes()不起作用

Android 试图在google地图上显示自定义标记时,BitmapDescriptor.fromBytes()不起作用,android,flutter,dart,google-maps-markers,marker,Android,Flutter,Dart,Google Maps Markers,Marker,我试图在谷歌地图上显示自定义图像作为标记。问题是位图描述符。fromAssetImage()工作正常,但位图描述符。fromBytes()不工作。由于我必须进一步使用画布,我需要使用BitmapDescriptor.fromBytes()。感谢您的帮助。下面是完整的代码 class AqiMapPage extends StatefulWidget { @override _AqiMapPageState createState() => _AqiMapPageState(); }

我试图在谷歌地图上显示自定义图像作为标记。问题是位图描述符。fromAssetImage()工作正常,但位图描述符。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);
            },
          );
        }
      },
    );
  }
}
class AqiMapPage扩展了StatefulWidget{
@凌驾
_AQIMAppagentate createState()=>AQIMAppagentate();
}
未来的getCustomMapMarker(int aqi)异步{
级别=AqiCnAqiRange.getAqiLevel(aqi);
//这是有效的
/*返回等待BitmapDescriptor.fromAssetImage(
图像配置(devicePixelRatio:2.5),
'资产/标记/${levels.markerIcon}')*/
//这不起作用
return wait _getAssetIcon(_context,'assets/markers/${levels.markerIcon}');
}
Future\u getAssetIcon(BuildContext上下文,字符串imageUrl)异步{
最终完成符bitmapIcon=
完成符();
最终图像配置配置=createLocalImageConfiguration(上下文);
AssetImage(imageUrl)
.resolve(配置)
.addListener(ImageStreamListener((ImageInfo图像,bool同步)异步{
最终字节数=
等待image.image.toByteData(格式:ImageByteFormat.png);
最终位图描述符位图=
BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());
bitmapIcon.complete(位图);
}));
返回等待bitmapIcon.future;
}
未来getMarkerList(列表映射数据)异步{
Set markerList=Set();
forEach((元素)异步{
试一试{
位图描述符位图描述符=
等待getCustomMapMarker(int.parse(element.aqi));
标记器=新标记器(
markerId:markerId(element.aqi),
位置:板条(element.lat,element.lon),
图标:位图描述符,
);
markerList.add(marker);
}捕获(e){
打印(如toString());
}
});
返回标记列表;
}
完成器控制器;
构建上下文(BuildContext)上下文;;
最终_scaffoldKey=GlobalKey();
类_AqiMapPageState扩展状态{
最后一次全球杯=
新GlobalKey();
AqiCnMapBloc集团;
@凌驾
void initState(){
super.initState();
_控制器=完成器();
_bloc=AqiCnMapBloc();
_bloc.getAqiCnMap(false);
}
@凌驾
小部件构建(构建上下文){
_上下文=上下文;
返回脚手架(
钥匙:_scaffoldKey,
appBar:appBar(
标题:文本(AppLocalizations.of)(上下文)
.getString(AppStringKeys.AQI_MAP_PAGE_KEY)),
标题:对,
),
backgroundColor:HexColor.fromHex(AppColor.scaffoldBackgroundColor),
正文:新的刷新指示器(
键:_refreshIndicatorKey,
onRefresh:()=>\ u bloc.getAqiCnMap(true),
孩子:StreamBuilder(
流:_bloc.akicnampstream,
生成器:(上下文,快照){
if(snapshot.hasData){
开关(快照、数据、状态){
案例状态。正在加载:
返回加载(加载键:snapshot.data.message);
打破
案例状态。成功:
返回AqiMapData(映射数据:snapshot.data.data);
打破
案例状态。错误:
返回错误(
错误:snapshot.data.message,
onRetryPressed:()=>_bloc.getAqiCnMap(false),
);
打破
}
}
返回容器();
},
),
),
);
}
}
类AqiMapData扩展了无状态小部件{
最终AQICN响应图数据;
const-akimapdata({Key-Key,this.mapData}):super(Key:Key);
@凌驾
小部件构建(构建上下文){
回归未来建设者(
future:getMarkerList(mapData.mapData),
生成器:(BuildContext上下文,异步快照){
如果(!snapshot.hasData){
//加载数据时:
返回不带文本的加载();
}否则{
//加载的数据:
返回谷歌地图(
mapType:mapType.hybrid,
myLocationEnabled:对,
//fixme-fix lat lng
初始摄像机位置:
摄像机位置(目标:LatLng(25.6185024,85.0726964),变焦:3),
标记:snapshot.data,
onMapCreated:(谷歌地图控制器){
_控制器。完成(控制器);
},
);
}
},
);
}
}

我找到了一个解决方案。虽然我不确定上面的代码有什么问题。但这似乎是某种同步或渲染问题。使用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);
      },
    );
  }
}
class AqiMapPage扩展了StatefulWidget{
@凌驾
_AQIMAppagentate createState()=>AQIMAppagentate();
}
最终_scaffoldKey=GlobalKey();
类_AqiMapPageState扩展状态{
最后一次全球杯=
新GlobalKey();
AqiCnMapBloc集团;
@凌驾
void initState(){
super.initState();
_bloc=AqiCnMapBloc();
_bloc.getAqiCnMap(false);
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
钥匙:_scaffoldKey,
appBar:appBar(
标题:文本(AppLocalizations.of)(上下文)
.getString(AppStringKeys.AQI_MAP_PAGE_KEY)),
标题:对,
),
backgroundColor:HexColor.fromHex(AppColor.scaffoldBackgroundColor),
正文:新的刷新指示器(
键:_refreshIndicatorKey,
onRefresh:()=>\ u bloc.getAqiCnMap(true),
孩子:StreamBuilder(
流:_bloc.akicnampstream,
生成器:(上下文,快照){
if(snapshot.hasData){
开关(快照、数据、状态){
案例状态。正在加载:
返回加载(加载键:snapshot.data.message);
打破