flutter_map通过BLoC移动带有Map控制器的相机

nnsrf1az  于 2023-11-21  发布在  Flutter
关注(0)|答案(5)|浏览(193)

我正在使用BLoC模式和flutter_map包构建一个flutter应用程序。我想将相机移动到特定位置。我试图将Map控制器传递到我的块结构并从那里移动相机,但我得到一个错误:
第一个月
我不确定这是不是正确的方法。

class HomePage extends StatelessWidget {
  const HomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
        providers: [
          ...,
          BlocProvider<MapBloc>(
            create: (BuildContext context) => MapBloc(mapController: MapController()) // passing map controller
            ..add(MapDataInit()),
          )
        ],
          ...
     );
  }
}

字符串
map_bloc.dart

class MapBloc extends Bloc<MapEvent, MapState> {
  final MapController mapController;
  LocationRepository _locationRepository = LocationRepository();

  MapBloc({@required this.mapController});

  @override
  get initialState => MapDataUninitialized();

  @override
  Stream<MapState> mapEventToState(MapEvent event) async* {
    final currentState = state;

    if (event is AddMarker) {
      yield MapDataLoaded(
          mapController: this.mapController,
          markers: [...]);
        this.add(MoveCamera(event.latLan)); // not sure about this
    }
    if (event is MoveCamera) {
      mapController.onReady.then((result) { // i'm getting an error here
        mapController.move(event.latLan, 15.0);   
      });
    }
  }
}


带有Map的Widget

class SelectLocationView extends StatelessWidget {
  Widget build(BuildContext context) {
    return BlocBuilder<MapBloc, MapState>(
          builder: (context, state) {
            ...
            if (state is MapDataLoaded) {
              return Container(
                child: Center(
                    child: Container(
                        child: FlutterMap(
                          mapController: state.mapController, // I'm trying to get previously defined controller
                  options: MapOptions(...),
                  layers: [
                    TileLayerOptions(
                        urlTemplate:
                            "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
                        subdomains: ['a', 'b', 'c']),
                    MarkerLayerOptions(...),
                  ],
                ))),
              );
            }
          },
        );
  }
}


我不知道为什么Map控制器的onReady方法有问题。

bmp9r5qi

bmp9r5qi1#

我在使用GetX时遇到了类似的问题。
我决定通过应用一些前提:首先,我在Widget(无状态)中保留了Map的任何和所有操作 ,因为我需要在google插件和flutter_map 之间切换。
然后,在控制器中(在BloC中的情况下),它只是触发必要的信息,以便视图从它那里接收必须居中的新位置,但视图是知道和集中Map的人,而不是BloC。
简而言之,我必须使用静态变量来保持应用程序中mapController的单例引用,因为“onReady()”方法只被调用一次,所以我保留了bool来控制map的状态,而“onReady“方法没有执行,我们无法访问map对象,如”zoom“和”move“。
我的示例代码:

class FlutterMapWidget extends StatelessWidget {

  static MapController _mapController;
  bool isMapRead = false;

  FlutterMapWidget() {
    // create instance only not exists another reference
    if(_mapController == null) {
      _mapController = MapController();
    }
    
    // after onReady, flag local control variable
    _mapController.onReady.then((v) {
      isMapRead = _mapController.ready;
    });
  }
  
  @override
  Widget build(BuildContext context) {

    return  Stack(
      children: [
        _buildMap(),
        // add another map components ...
      ],
    );

  }
  
  void _gotoLocation(double lat,double long) {
    //check if map is ready to move camera...
    if(this.isMapRead) {
      _mapController.move(LatLng(lat, long), _mapController?.zoom);
    }
  }

  Widget _buildMap(){

    return GetBuilder<MapEventsController>( // GetX state control
      init: _mapEventsController, // GetX events controller
      builder: (value) { // GetX event fire when update state in controller

        updatePinOnMap(value.liveUpdate, value.location);

        if(value.liveUpdate){
          _gotoLocation(value.location.lat, value.location.lng);
        }

        return FlutterMap(
          mapController: _mapController,
          options: MapOptions(
            center: LatLng(value?.location?.lat, value?.location?.lng),
            zoom: 13.0,
            plugins: [
            ],
            onTap: _handleTap,
          ),
          layers: [
            TileLayerOptions(
                urlTemplate:
                'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
                subdomains: ['a', 'b', 'c']
            ),
            MarkerLayerOptions(markers: markers), //markers
          ],
        );
      },
    );

  }

  void updatePinOnMap(bool liveUpdate, Location location) async {

    if(location == null) {
      return;
    }

    this.markers.clear();

    Marker mark = Marker(
      point: LatLng(location.lat, location.lng),
      anchorPos: anchorPos,
      builder: (ctx) =>
        GestureDetector(
          onTap: () => _configureModalBottomSheet(ctx),
          child: Container(
            child: Icon(Icons.my_location, size: 28, color: Colors.red,), // FlutterLogo(),
          ),
        ),
    );

    markers.add(mark);

  }

  void _handleTap(LatLng latlng) {
    
  }
  
  void _configureModalBottomSheet(context) {
  
  }

}

字符串

oalqel3c

oalqel3c2#

听起来很傻,但是你正在初始化Map控制器吗?

ovfsdjhp

ovfsdjhp3#

如果你使用BLoC(作为状态管理),这里有一个例子,你可以在没有controller的情况下完成它。
1.把你的FlutterMap小工具放在你的自定义小工具里。
1.在调用这个小部件时,使用key并使用BlocBuilder Package 它。结果,FlutterMap小部件将重新构建新的中心。
范例:

class _MapView extends StatelessWidget {
  const _MapView();

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<MapBloc, MapState>(
      builder: (context, state) {
        return Scaffold(
          body: MapWidget(
            key: Key('map${state.latitude}${state.longitude}'),
            latitude: state.latitude,
            longitude: state.longitude,
          ),
        );
      },
    );
  }
}

class MapWidget extends StatelessWidget {
  const MapWidget({
    super.key,
    required this.latitude,
    required this.longitude,
  });

  final double latitude;
  final double longitude;

  @override
  Widget build(BuildContext context) {
    final _searchingPoint = LatLng(
      latitude,
      longitude,
    );
    return FlutterMap(
      options: MapOptions(
        center: _searchingPoint,
        zoom: 11,
        keepAlive: true,
      ),
    );
  }
}

字符串
来源:GitHub

wsxa1bj1

wsxa1bj14#

上面的答案是正确的,但我会补充一件事,这对我来说也是一个大问题。如何根据用户缩放保持缩放级别因为当你监听当前位置的变化并根据它更新相机位置时,缩放级别也会选择你在开始时提供的缩放级别。

  • 例如:* 你在开始时提供缩放级别13,然后将屏幕缩放到16,然后当相机位置更新时,它会再次将你带到缩放级别13,并且每秒都在重复,这真的很烦人,所以你必须动态提供缩放级别这将根据用户缩放级别而变化。

首先听一下位置流:

location.onLocationChanged.listen((event) {
final newLatLng = LatLng(event.latitude!, event.longitude!);
// Use mapController to access the move method
// move() method is used for the camera position changing e.g: move(LatLng center,   double zoom)
mapController.move(newLatLng , 13);  // this will set the zoom level static to 13
// but we want it to be dynamic according to the user zoom level,
// so then use the mapController.zoom property will dynamically adjust your zoom level
 mapController.move(newLatLng , mapController.zoom); 
});

字符串

jdg4fx2g

jdg4fx2g5#

你也可以用BLOC来实现,只要使用一个BlocListener并根据你的状态更新Controller值,无论何时状态改变

Widget build(BuildContext context) {
    //create your map controller
    MapController mapController = MapController();
    ...
    //Attach a listener that is called when a state changes and control the MapController
    return BlocListener<AddFindingScreenBloc, AddFindingScreenState>(
        listener: (context, state) {
            mapController.move(LatLng(state.latitude, state.longitude), state.zoom);
         },
      child: 
          ...
          FlutterMap(
              mapController: mapController
     );

字符串

相关问题