felangel / bloc

A predictable state management library that helps implement the BLoC design pattern
https://bloclibrary.dev
MIT License
11.86k stars 3.4k forks source link

using bloc to change google map field #1774

Closed ezra126 closed 4 years ago

ezra126 commented 4 years ago

I am using bloc for my project. and am a bit confused about how to use it clearly. in a nutshell, my project mostly uses google map which is like ride-hailing app.and I want to change only google map property based on state change rather than creating new instance of google map for each state change .my aim was to add onCameraMove property when it is on destinationnotselected state not on other state but onCameramove property not updated once it once destinationnotselected state I use this below two approach but neither of them not worked.so do I need to create the different screen for the state navigating to other screen or I can just use homescreen by changing the Googlemap property based on state. in my home screen, I created a stack with google map on it.which can be changed based on state change .

The first approach which I don't want to create multiple GoogleMap instance for each state

 child: BlocBuilder<DeliveryBookingBloc, DeliveryBookingState>(
          builder: (context,state){
            if(state is DeliveryBookingNotInitializedState){
              return GoogleMap(
                  mapType:  MapType.normal,
                  zoomControlsEnabled: false,
                  zoomGesturesEnabled: true,
                  scrollGesturesEnabled: true,
                  compassEnabled: true,
                  rotateGesturesEnabled: true,
                  tiltGesturesEnabled: true,
                  myLocationEnabled: true,
                  myLocationButtonEnabled: false,
                  gestureRecognizers: < Factory < OneSequenceGestureRecognizer >> [
                    new Factory < OneSequenceGestureRecognizer > (
                          () => new EagerGestureRecognizer(),
                    ),
                  ].toSet(),
                  initialCameraPosition: initialCameraPosition,
                  onMapCreated: (GoogleMapController controller) async {
                    //BlocProvider.of<MapBloc>(context).mapLoaded();
                    if (mounted) {
                      setState(() {
                        mapController = controller;

                      });
                    }
                    await location.getLocation().then((LocationData initialLoc) {
                      LatLng latLng = LatLng(initialLoc.latitude, initialLoc.longitude);
                      CameraUpdate cameraUpdate = CameraUpdate.newLatLngZoom(latLng, 16);
                      mapController.animateCamera(cameraUpdate);
                    });

                  });
            }
            if (state is DestinationNotSelectedState) {
              return GoogleMap(
                  mapType: MapType.normal,
                  zoomControlsEnabled: false,
                  zoomGesturesEnabled: true,
                  scrollGesturesEnabled: true,
                  compassEnabled: true,
                  rotateGesturesEnabled: true,
                  tiltGesturesEnabled: true,
                  myLocationEnabled: true,
                  myLocationButtonEnabled: false,
                  markers: markers,
               ---->    onCameraMove: ((_position) =>
                      _updatePosition(_position, "ndfkjnkjdf")),
                  gestureRecognizers: <Factory <OneSequenceGestureRecognizer>>[
                    new Factory <OneSequenceGestureRecognizer> (
                          () => new EagerGestureRecognizer(),
                    ),
                  ].toSet(),
                  initialCameraPosition: initialCameraPosition,
                  onMapCreated: (GoogleMapController controller) async {
                    //BlocProvider.of<MapBloc>(context).mapLoaded();
                    if (mounted) {
                      setState(() {
                        mapController = controller;
                      });
                    }

                  });

second approach changing only onCameraMove property based on the state

 child: BlocBuilder<DeliveryBookingBloc, DeliveryBookingState>(
          builder: (context,state){
              return GoogleMap(
                  mapType: MapType.normal,
                  zoomControlsEnabled: false,
                  zoomGesturesEnabled: true,
                  scrollGesturesEnabled: true,
                  compassEnabled: true,
                  rotateGesturesEnabled: true,
                  tiltGesturesEnabled: true,
                  myLocationEnabled: true,
                  myLocationButtonEnabled: false,
                  markers: markers,
                  onCameraMove: (state is DestinationNotSelectedState) ? ((_position) => _updatePosition()) : null,
                  gestureRecognizers: <Factory <OneSequenceGestureRecognizer>>[
                    new Factory <OneSequenceGestureRecognizer> (
                          () => new EagerGestureRecognizer(),
                    ),
                  ].toSet(),
                  initialCameraPosition: initialCameraPosition,
                  onMapCreated: (GoogleMapController controller) async {
                    //BlocProvider.of<MapBloc>(context).mapLoaded();
                    if (mounted) {
                      setState(() {
                        mapController = controller;
                      });
                    }

                  });

https://github.com/ezra126/bekloh_user/tree/authentication thanks in advance

felangel commented 4 years ago

Hi @ezra126 👋 Thanks for opening an issue!

You can just use a BlocListener and update the camera position via the GoogleMapController.

class _MyMapState extends State<MyMap> {
  GoogleMapController _controller;

  @override
  Widget build(BuildContext context) {
    return BlocListener<DeliveryBookingBloc, DeliveryBookingState>(
      listener: (context, state) {
        // interact with controller to update camera based on state
        _controller?.animateCameraPosition(...);
      },
      child: GoogleMap(
        ...,
        onMapCreated: (controller) => _controller = controller,
      ),
  }
}

Let me know if that helps 👍

ezra126 commented 4 years ago

hi @felangel thanks for the reply but my aim was to change initialCameraPosition and onCameramove property and display it on two different screen (homeScreen and addDestinationscreen) and it is not working adding this on BlocListner. and this property can not be changed using a controller that's why I am confused.

DeliveryMap.dart

return Scaffold(
      body: BlocListener<DeliveryBookingBloc, DeliveryBookingState>(
        listener: (BuildContext context, DeliveryBookingState state) {
          if (state is DeliveryBookingNotInitializedState) {
             initialCameraPosition = CameraPosition(zoom: 8, target: LatLng(9.005401, 38.763611));
           // clearData();
          }
          if (state is DestinationNotSelectedState) {
               //clearData();
                initialCameraPosition = CameraPosition(   zoom: 10,   target: LatLng(29.005401, 58.763611));

        addMarker();
          }
        },
        child: GoogleMap(
                  initialCameraPosition: initialCameraPosition,   < ----- change this based on the state
                  mapType: MapType.normal,
                  zoomControlsEnabled: false,
                  zoomGesturesEnabled: true,
                  myLocationEnabled: true,
                  myLocationButtonEnabled: false,
                  onCameraMove: ((_position) => _updatePosition(_position, "ndfkjnkjdf"))  ,
                  onMapCreated: (GoogleMapController controller) async {
                    //BlocProvider.of<MapBloc>(context).mapLoaded();
                    if (mounted) {
                      setState(() {
                        mapController = controller;
                      });
                    }
                    await location.getLocation().then((LocationData initialLoc) {
                      LatLng latLng =
                          LatLng(initialLoc.latitude, initialLoc.longitude);
                      CameraUpdate cameraUpdate =
                          CameraUpdate.newLatLngZoom(latLng, 16);
                      mapController.animateCamera(cameraUpdate);
                    });
                  })

homescreen.dart

 body: Stack(
                     children: [
                       HomeAppbar("Home")
                       DeliveryMap(),      <--------- adding the Map widget right here
                    ]
)

addDestination.dart

 body: Stack(
                     children: [
                       HomeAppbar("Add Destination")
                       DeliveryMap(),      <--------- adding the Map widget right here
                    ]
)
felangel commented 4 years ago

I’m not sure I understand. The initialCameraPosition is intended to be used once when the map is created and onCameraMove should ideally just notify the bloc and allow you to update the bloc state accordingly.

felangel commented 4 years ago

Closing for now but feel free to comment with additional information/questions and I'm happy to continue the conversation 👍