animateCamera works and moveCamera doesn't for GoogleMap - Android

后端 未结 4 1472
感情败类
感情败类 2021-01-14 16:36

I need to move Camera to cover all Markers on it. So, I build LatLngBounds and then try to call mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(latLng

相关标签:
4条回答
  • 2021-01-14 16:47

    Thanks to @Viacheslav I made the same in setOnCameraIdleListener:

    override fun onMapReady(googleMap: GoogleMap?) {
        this.googleMap = googleMap
    
        // setupMap()
    
        googleMap?.setOnCameraIdleListener {
            // Remove the listener to stop calling the same event.
            googleMap.setOnCameraIdleListener(null)
    
            // Now you can use 'moveCamera'.
            // I also added a delay of 100 ms here in order to draw the map 
            // and correctly calculate distances. If this is your case, then add a short pause.
            val position = LatLng(latitude, longitude)
            val camera = CameraUpdateFactory.newLatLngZoom(position, 10)
            // Strange, but it doesn't work for
            // val camera = CameraUpdateFactory.zoomTo(10)
            googleMap.moveCamera(camera)
    
            // If you later want to listen to camera movements (start-stop),
            // you should change setOnCameraIdleListener here.
            googleMap.setOnCameraIdleListener{
                // A listener for future camera stops.
                ...
            }
        }
    }
    

    setOnCameraIdleListener is an appropriate listener to move camera and calculate distances. You can also get the same with delay (100-300 ms) inside onMapReady.

    0 讨论(0)
  • 2021-01-14 16:52

    As per documentation , this API can't be used before the map has undergone layout. It says

    Note: Only use the simpler method newLatLngBounds(boundary, padding) to generate a CameraUpdate if it is going to be used to move the camera after the map has undergone layout. During layout, the API calculates the display boundaries of the map which are needed to correctly project the bounding box. In comparison, you can use the CameraUpdate returned by the more complex method newLatLngBounds(boundary, width, height, padding) at any time, even before the map has undergone layout, because the API calculates the display boundaries from the arguments that you pass.

    But you can make use of newLatLngBounds() method in OnCameraChangeListener. Everything will work perfectly and you don't need to calculate screen size. As far as I know, this event occurs after map size calculation.

        mMap.setOnCameraChangeListener(new OnCameraChangeListener() {
    
        @Override
        public void onCameraChange(CameraPosition arg0) {
            // Move camera.
            mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 15));
            // Remove listener to prevent position reset on camera move.
            mMap.setOnCameraChangeListener(null);
        }
    });
    
    0 讨论(0)
  • 2021-01-14 16:54

    As clearly documented here OnMapReadyCallback

    Note that OnMapReadyCallback does not guarantee that the map has undergone layout. Therefore, the map's size may not have been determined by the time the callback method is called. If you need to know the dimensions or call a method in the API that needs to know the dimensions, get the map's View and register an ViewTreeObserver.OnGlobalLayoutListener as well.

    Do not chain the OnMapReadyCallback and OnGlobalLayoutListener listeners, but instead register and wait for both callbacks independently, since the callbacks can be fired in any order.

    So you have to use both (onMapReady,onGlobalLayout) callbacks to make sure that map have been fully loaded and size has been determined.

    private GoogleMap mMap;
    private boolean isMapLoaded;
    
    SupportMapFragment mapFragment = (SupportMapFragment)getSupportFragmentManager()
                .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    mapFragment.getView().getViewTreeObserver().addOnGlobalLayoutListener(this);
    
    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        if (!isMapLoaded) {
            isMapLoaded = true;
            return;
        }
        initMap();
    }
    
    @Override
    public void onGlobalLayout() {
        if (!isMapLoaded) {
            isMapLoaded = true;
            return;
        }
        initMap();
    }
    
    private void initMap() {
       //maps fully loaded instance with defined size will be available here.
       //mMap.animateCamera();
       //mMap.moveCamera();
    }
    
    0 讨论(0)
  • 2021-01-14 16:59

    Since Google Maps SDK was updated to recent versions onCameraChangeListener became deprecated. I've also faced with this problem and I discovered that onCameraIdleListener does the similar trick. As I see so far it's callback method onCameraIdle called always after onMapReady. So my approach looks like this piece of code (considering it put in Activity) for Google Maps SDK 9.6+:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // set content view and call getMapAsync() on MapFragment
    }
    
    @Override
    public void onMapReady(GoogleMap googleMap) {
        map = googleMap;
        map.setOnCameraIdleListener(this);
        // other initialization stuff
    }
    
    @Override
    public void onCameraIdle() {
        /* 
           Here camera is ready and you can operate with it. 
           you can use 2 approaches here:
    
          1. Update the map with data you need to display and then set
             map.setOnCameraIdleListener(null) to ensure that further events
             will not call unnecessary callback again.
    
          2. Use local boolean variable which indicates that content on map
             should be updated
        */
    }
    
    0 讨论(0)
提交回复
热议问题