Inicio Android Mapas en Android – Google Maps Android API (2)

Mapas en Android – Google Maps Android API (2)

por sgoliver
mapas-2

[mensaje-curso]

En el artículo anterior del curso vimos cómo realizar todos los preparativos necesarios para comenzar a utilizar la API de Google Maps para Android, a destacar: crear un nuevo proyecto en la consola de desarrolladores, obtener una nueva API Key, y configurar un proyecto básico en Android Studio.

En esta segunda entrega vamos a hacer un repaso de las opciones básicas de un mapa:

  • Cambiar las propiedades generales del mapa, como por ejemplo el tipo de vista (satélite, terreno, …) y la activación/desactivación de determinados controles superpuestos.
  • Movernos por el mapa de forma programática.
  • Obtener los datos de la posición actual mostrada en el mapa.
  • Responder a los eventos principales del mapa.

Como aplicación de ejemplo (que podéis descargar al final de este artículo), tomaremos como base la ya creada en el artículo anterior, a la que añadiremos varios botones superiores para demostrar el funcionamiento de las acciones anteriores. El layout lo mantendré muy sencillo, quedaría de la siguiente forma:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent" >

    <Button android:id="@+id/btnOpciones"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/opciones" />

    <Button android:id="@+id/btnMover"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/btnOpciones"
        android:text="@string/mover" />

    <Button android:id="@+id/btnAnimar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/btnMover"
        android:text="@string/animar" />

    <Button android:id="@+id/btnPosicion"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/btnAnimar"
        android:text="@string/pos" />

    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/btnOpciones" />

</RelativeLayout>

Si hacemos un poco de memoria, recordaremos cómo en la antigua versión de la API de Google Maps era bastante poco homogéneo el acceso y modificación de determinados datos del mapa. Por ejemplo, la consulta de la posición actual o la configuración del tipo de mapa se hacían directamente sobre el control MapView, mientras que la manipulación de la posición y el zoom se hacían a través del controlador asociado al mapa (MapController). Además, el tratamiento de las coordenadas y las unidades utilizadas eran algo peculiares, teniendo estar continuamente convirtiendo de grados a microgrados y de éstos a objetos GeoPoint, etc.

Con la API actual, todas las operaciones se realizarán directamente sobre el objeto GoogleMap, el componente base de la API. En el artículo anterior acabamos viendo cómo obtener, dentro del evento onMapReady(), una referencia al objeto GoogleMap incluido en el MapFragment que añadimos a nuestro layout principal. En este nuevo artículo continuaremos a partir de ese punto para realizar diferentes acciones sobre el mapa.

Así, por ejemplo, para modificar el tipo de vista mostrada en el mapa podremos utilizar una llamada a su método setMapType(),  pasando como parámetro el tipo de mapa, a elegir entre los siguientes:

  • GoogleMap.MAP_TYPE_NORMAL. Mapa de carreteras normal.
  • GoogleMap.MAP_TYPE_SATELLITE. Imágenes de satélite.
  • GoogleMap.MAP_TYPE_HYBRID. Una mezcla de los dos anteriores.
  • GoogleMap.MAP_TYPE_TERRAIN. Mapa topográfico.

Otra de las opciones que podemos cambiar son los indicadores y controles a mostrar sobre el mapa. Por ejemplo, para que se visualicen los controles de zoom, podemos llamar al método getUiSettings() del mapa para acceder a sus opciones de visualización, y sobre éste al método setZoomControlsEnabled().

Como demostración añadiremos al primero de los botones de nuestra interfaz el cambio de las dos opciones comentadas, que quedaría de la siguiente forma:

btnOpciones = (Button)findViewById(R.id.btnOpciones);
btnOpciones.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        cambiarOpciones();
    }
});

//...

private void cambiarOpciones()
{
    mapa.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
    mapa.getUiSettings().setZoomControlsEnabled(true);
}

El efecto sobre el mapa en la aplicación sería el siguiente:

tipo-mapa-satelite

En cuanto al movimiento sobre el mapa, podremos mover libremente nuestro punto de vista (o cámara, como lo han llamado los chicos de Android) por un espacio 3D. De esta forma, ya no sólo podremos hablar de latitud-longitud (target) y zoom, sino también de orientación (bearing) y ángulo de visión (tilt). La manipulación de los 2 últimos parámetros unida a posibilidad actual de ver edificios en 3D de muchas ciudades nos abren un mundo de posibilidades.

El movimiento de la cámara se va a realizar siempre mediante la construcción de un objeto CameraUpdate con los parámetros necesarios. Para los movimientos más básicos como la actualización de la latitud y longitud o el nivel de zoom podremos utilizar la clase CameraUpdateFactory y sus métodos estáticos que nos facilitará un poco el trabajo.

Así por ejemplo, para cambiar sólo el nivel de zoom podremos utilizar los siguientes métodos para crear nuestro CameraUpdate:

  • CameraUpdateFactory.zoomIn(). Aumenta en 1 el nivel de zoom.
  • CameraUpdateFactory.zoomOut(). Disminuye en 1 el nivel de zoom.
  • CameraUpdateFactory.zoomTo(nivel_de_zoom). Establece el nivel de zoom.

Por su parte, para actualizar sólo la latitud-longitud de la cámara podremos utilizar:

  • CameraUpdateFactory.newLatLng(lat, long). Establece la lat-lng expresadas en grados.

Si queremos modificar los dos parámetros anteriores de forma conjunta, también tendremos disponible el método siguiente:

  • CameraUpdateFactory.newLatLngZoom(lat, long, zoom). Establece la lat-lng y el zoom.

Para movernos lateralmente por el mapa (panning) podríamos utilizar los métodos de scroll:

  • CameraUpdateFactory.scrollBy(scrollHorizontal, scrollVertical). Scroll expresado en píxeles.

Tras construir el objeto CameraUpdate con los parámetros de posición tendremos que llamar a los métodos moveCamera() o animateCamera() de nuestro objeto GoogleMap, dependiendo de si queremos que la actualización de la vista se muestre directamente en un solo paso o bien de forma animada.

Con esto en cuenta, si quisiéramos por ejemplo centrar la vista en Madrid (España) con un zoom de nivel 5, y lo haremos en el segundo de los botones de la aplicación de ejemplo, podríamos hacer lo siguiente:

btnMover = (Button)findViewById(R.id.btnMover);
btnMover.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        moverMadrid();
    }
});

//...

private void moverMadrid()
{
    CameraUpdate camUpd1 =
        CameraUpdateFactory
            .newLatLngZoom(new LatLng(40.41, -3.69), 5);

    mapa.moveCamera(camUpd1);
}

Veamos el resultado sobre la aplicación:

mover-madrid

Además de los movimientos básicos que hemos comentado, si queremos modificar los demás parámetros de la cámara (orientación e inclinación) o varios de ellos simultáneamente tendremos disponible el método más general CameraUpdateFactory.newCameraPosition() que recibe como parámetro un objeto de tipo CameraPosition. Este objeto los construiremos indicando todos los parámetros de la posición y orientación de la cámara a través de su método Builder().

Así, por ejemplo, si quisiéramos mostrar de una forma más estética el monumento a Alfonso XII de Madrid podríamos hacerlo de la siguiente forma, lo haremos en el tercer botón de demostración de la aplicación de ejemplo:

btnAnimar = (Button)findViewById(R.id.btnAnimar);
btnAnimar.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        animarMadrid();
    }
});

//...

private void animarMadrid()
{
    LatLng madrid = new LatLng(40.417325, -3.683081);

    CameraPosition camPos = new CameraPosition.Builder()
        .target(madrid)   //Centramos el mapa en Madrid
        .zoom(19)         //Establecemos el zoom en 19
        .bearing(45)      //Establecemos la orientación con el noreste arriba
        .tilt(70)         //Bajamos el punto de vista de la cámara 70 grados
        .build();

    CameraUpdate camUpd3 =
        CameraUpdateFactory.newCameraPosition(camPos);

    mapa.animateCamera(camUpd3);
}

Como podemos comprobar, mediante este mecanismo podemos modificar todos los parámetros de posición de la cámara (o sólo algunos de ellos) al mismo tiempo. En nuestro caso de ejemplo hemos centrado la vista del mapa sobre el parque de El Retiro de Madrid (España), con un nivel de zoom de 19, una orientación de 45 grados para que el noreste esté hacia arriba y un ángulo de visión de 70 grados de forma que veamos en 3D el monumento a Alfonso XII en la vista de mapa NORMAL. En la siguiente imagen vemos el resultado:

animar-madrid

Como podéis ver, la API actual de mapas facilita bastante el posicionamiento dentro del mapa, y el uso de las clases CameraUpdate y CameraPosition resulta bastante intuitivo.

Bien, pues ya hemos hablado de cómo modificar nuestro punto de vista sobre el mapa, pero si el usuario se mueve de forma manual por él, ¿cómo podemos conocer en un momento dado la posición de la cámara?

Pues igual de fácil, mediante el método getCameraPosition(), que nos devuelve un objeto CameraPosition como el que ya conocíamos. Accediendo a los distintos métodos y propiedades de este objeto podemos conocer con exactitud la posición de la cámara, la orientación y el nivel de zoom. En la aplicación de ejemplo añadiré la demostración de esto en el cuarto de los botones añadidos, que mostrará un mensaje toast con la posición actual de la cámara.

btnPosicion = (Button)findViewById(R.id.btnPosicion);
btnPosicion.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        obtenerPosicion();
    }
});

//...

private void obtenerPosicion()
{
    CameraPosition camPos = mapa.getCameraPosition();

    LatLng coordenadas = camPos.target;
    double latitud = coordenadas.latitude;
    double longitud = coordenadas.longitude;

    Toast.makeText(this, "Lat: " + latitud + " | Long: " + longitud, Toast.LENGTH_SHORT).show();
}

Veamos un ejemplo sobre la propia aplicación:

get-latitud-longitud

Por último, vamos a ver cómo responder a ciertos eventos del mapa, entre los que destaco el click y el cambio de posición. Para responder a estos eventos definiremos los listener correspondientes sobre nuestro objeto GoogleMap.

Para responder a los clicks del usuario sobre el mapa definiremos el evento onMapClick() llamando al método setOnMapClickListener() del mapa. Dentro de éste recibiremos un objeto LatLng con la posición geográfica, la que mostraremos en un mensaje tipo toast junto a la posición X-Y de pantalla (dentro de la vista actual del mapa) donde el usuario ha pulsado. Para obtener esta posición usaremos el método toScreenLocation() del objeto Projection que podemos obtener a partir del mapa llamando a getProjection().

mapa.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
    public void onMapClick(LatLng point) {
        Projection proj = mapa.getProjection();
        Point coord = proj.toScreenLocation(point);

        Toast.makeText(
            MainActivity.this,
            "Click\n" +
            "Lat: " + point.latitude + "\n" +
            "Lng: " + point.longitude + "\n" +
            "X: " + coord.x + " - Y: " + coord.y,
            Toast.LENGTH_SHORT).show();
    }
});

Un ejemplo sobre la aplicación sería el siguiente:

evento-click

Por su parte, para responder a cambios de posición de la cámara (por ejemplo cuando el usuario desplaza el mapa con el gesto habitual del dedo) debemos definir el evento onCameraChange() llamando al método setOnCameraChangeListener(). Este evento recibe un objeto de tipo CameraPosition, por lo que podremos acceder a cualquier de los datos de posición encapsulados por dicho objeto (latitud, longitud, zoom, orientación, …).

mapa.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
    public void onCameraChange(CameraPosition position) {
        Toast.makeText(
            MainActivity.this,
            "Cambio Cámara\n" +
            "Lat: " + position.target.latitude + "\n" +
            "Lng: " + position.target.longitude + "\n" +
            "Zoom: " + position.zoom + "\n" +
            "Orientación: " + position.bearing + "\n" +
            "Ángulo: " + position.tilt,
            Toast.LENGTH_SHORT).show();
    }
});

Sobre nuestra aplicación de ejemplo quedaría de la siguiente forma:

evento-camara

Y con esto habríamos terminado de describir las acciones básicas de configuración y movimiento sobre el mapa. En los próximos artículos veremos más opciones, como la forma de añadir marcadores o dibujar sobre el mapa.

Puedes consultar y/o descargar el código completo de los ejemplos desarrollados en este artículo accediendo a la pagina del curso en GitHub.

[mensaje-curso]

You may also like

3 comentarios

Mapas en Android – Google Maps Android API [Serie] | sgoliver.net 13/09/2016 - 10:01

[…] Mapas en Android – Google Maps Android API (2) [Act. Septiembre 2016] […]

Responder
Mapas en Android – Google Maps Android API (3) | sgoliver.net 15/09/2016 - 16:39

[…] los dos artículos anteriores (I y II) del curso hemos visto cómo crear aplicaciones utilizando la API de Google Maps para Android y […]

Responder
David 17/03/2017 - 0:03

Y las clase Point?

Responder

Dejar un comentario

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies