12.4: Gestire l’evento click sui segnaposto della mappa

Condividi su:

Passo dopo passo stiamo apprendendo come personalizzare le mappe fornite da Google Maps per renderle utili allo scopo delle nostre app. Adesso sappiamo come effettuare il setup di una mappa, come gestire uno o più segnaposto personalizzandoli e come aggiungere delle informazioni a queste. Siamo inoltre in grado di spostare la camera sulla mappa, modificando di fatto la vista.





Cliccando sui segnaposto, così come sono, viene semplicemente visualizzato il titolo associato a questi. Questo è un comportamento di default quindi funziona senza che noi facciamo nulla. Se invece volessimo fare anche altro nel momento in cui l’utente clicca su un segnaposto?

La cosa è molto semplice e di fatto l’evento viene gestito così come vengono gestiti tutti gli eventi di questo tipo su Android. Basta collegare un listener all’oggetto su cui vogliamo monitorare gli eventi click e predisporre un oggetto che gestisca l’evento.

Tra le varie API è fornita anche l’interfaccia OnMarkerClickListener. Questa offre un unico metodo, “onMarkerClick()” che viene invocato nel momento in cui si verifica l’evento click su un segnaposto.
Come già facciamo per gli eventi click sulle view, implementiamo l’interfaccia del listener nell’Activity ed effettuiamo l’override del metodo astratto fornito da questa:

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleMap.OnMarkerClickListener {

    private static final String TAG = "MapsActivity";

    private GoogleMap mMap;
    /*
     * Definiamo una serie di cordinate sottoforma di costanti
     */
    private final static LatLng COLOSSEO = new LatLng(41.8902142,12.4900422);
    private final static LatLng PIAZZA_PLEBISCITO = new LatLng(40.8364761,14.2460472);
    private final static LatLng DUOMO_MILANO = new LatLng(45.4641013,9.1897378);
    private final static LatLng TORRE_PISA = new LatLng(43.7229559,10.3944083);

    /*
     * Dichiariamo gli oggetti segnaposto
     */
    private Marker mColosseo;
    private Marker mPlebiscito;
    private Marker mDuomoMilano;
    private Marker mTorrePisa;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }


    /**
     * Manipulates the map once available.
     * This callback is triggered when the map is ready to be used.
     * This is where we can add markers or lines, add listeners or move the camera. In this case,
     * we just add a marker near Sydney, Australia.
     * If Google Play services is not installed on the device, the user will be prompted to install
     * it inside the SupportMapFragment. This method will only be triggered once the user has
     * installed Google Play services and returned to the app.
     */
    @Override
    public void onMapReady(GoogleMap googleMap) {
        //Recuperiamo l'istanza di GoogleMap, quindi la mappa
        mMap = googleMap;

        //Lista di segnaposto istanziata e sfruttata solo per motivi di logging
        List<Marker> markerList = new ArrayList<>();

        //Settiamo il tipo di mappa da visualizzare, ad esempio una mappa ibrida
        mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);

        /*
         * Aggiungiamo i vari segnaposto alla mappa e contestualmente li personalizziamo.
         * Col metodo "setTag()" colleghiamo un oggetto al segnaposto
         * Avendo una lista, man mano li aggiungiamo anche a questa.
         */
        mColosseo = mMap.addMarker(new MarkerOptions()
                .position(COLOSSEO)
                .title(getResources().getString(R.string.colosseo))
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
        mColosseo.setTag(0);
        markerList.add(mColosseo);

        mPlebiscito = mMap.addMarker(new MarkerOptions()
                .position(PIAZZA_PLEBISCITO)
                .title(getResources().getString(R.string.piazza_plebiscito))
                .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));
        mPlebiscito.setTag(0);
        markerList.add(mPlebiscito);

        mDuomoMilano = mMap.addMarker(new MarkerOptions()
                .position(DUOMO_MILANO)
                .title(getResources().getString(R.string.duomo_milano))
                .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
        mDuomoMilano.setTag(0);
        markerList.add(mDuomoMilano);

        mTorrePisa = mMap.addMarker(new MarkerOptions()
                .position(TORRE_PISA)
                .title(getResources().getString(R.string.torre_pisa))
                .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW)));
        mTorrePisa.setTag(0);
        markerList.add(mTorrePisa);
        
        //Settiamo il listener su tutti i segnaposto della mappa
        mMap.setOnMarkerClickListener(this);
        
        for (Marker m : markerList){
            Log.d(TAG, "Marker: " + m.getTitle());
        }

        //Spostiamo la vista con un'animazione
        mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(COLOSSEO, 5));

//        LatLng sydney = new LatLng(-34, 151);
//        LatLng colosseo = new LatLng(41.8902142,12.4900422);
//
//        //Aggiungiamo il segnaposto, specificando colore, etichetta e colore
//        mMap.addMarker(new MarkerOptions().position(colosseo).title("Colosseo")
//        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_CYAN)));
//
//        //Spostiamo la visuale sopra le cordinate da mostrare ed effettuiamo uno zoom
//        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(colosseo, 15));
    }

    @Override
    public boolean onMarkerClick(Marker marker) {
        //All'interno di un oggetto intero salviamo l'oggetto memorizzato nel tag del segnaposto
        Integer clickCount = (Integer) marker.getTag();
        
        /*
         * Sfrutteremo l'oggetto salvato nel tag come un contatore di click sul segnaposto.
         * Semplicemente ad ogni click incrementiamo il suo valore, lo salviamo nel tag e 
         * visualizziamo un toast col numero di clik effettuati
         */
        if (clickCount != null) {
            clickCount++;

            marker.setTag(clickCount);

            Toast.makeText(MapsActivity.this, marker.getTitle() +
            getResources().getString(R.string.has_been_clicked) +
            clickCount + getResources().getString(R.string.times),
                    Toast.LENGTH_LONG).show();
        }

        return false;
    }
}

Come potete notare, una volta costruiti tutti i segnaposto, abbiamo settato il listener apposito sull’istanza della mappa, così possiamo gestire i click su tutti questi, a prescindere da quanti ce ne siano. Sarebbe infatti assurdo settare il listener segnaposto per segnaposto. Avendo implementato l’interfaccia all’interno della classe, l’oggetto di gestione evento sarà l’activity stessa (è qui che effettuiamo l’override del metodo di gestione), quindi come parametro passiamo il riferimento a questa.

L’idea è quella di conteggiare i click sui vari segnaposti. Avendo la possibilità di associare un oggetto ad ognuno di questi tramite il metodo “setTag()”, il conteggio lo salveremo in questo oggetto. È per questo motivo che a tutti abbiamo settato un tag 0, semplice inizializzazione dell’oggetto utile a questo scopo.

“onMarkerClick()” ha come parametro il segnaposto interessato dall’evento, quindi non facciamo altro che salvare il contenuto del tag associato a questo in un oggetto Integer; lo incrementiamo, per conteggiare il click appena avvenuto, e salviamo il nuovo valore nel tag. Come feedback all’utente visualizziamo un toast col numero di click avvenuti.
Per sicurezza, prima di qualsiasi operazione, verifichiamo che il tag esista.



Provando l’app noterete come ogni segnaposto avrà il proprio conteggio, poiché ognuno ha il suo oggetto associato come tag.

Il metodo “onMarkerClick()” ha anche un valore booleano di ritorno. Lo possiamo sfruttare per evitare o meno il comportamento di default. Con “false” verrà sia eseguito il comportamento di default, cioè la visualizzazione del titolo del segnaposto e lo spostamento della camera per centrarlo, che le nostre istruzioni, cioè il conteggio. Con true verrà ovviamente eseguito solo il conteggio.

Anche con questo articolo abbiamo finito, col prossimo ci occuperemo della localizzazione del dispositivo.

Condividi su:

label, , , ,

About the author