Thursday, January 17, 2013

Create custom info contents for GoogleMaps V2, by implementing custom InfoWindowAdapter

GoogleMap V2 with custom info contents


Create /res/layout/custom_info_contents.xml to define the layout of our custom info contents.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="5dp"
            android:adjustViewBounds="true"
            android:src="@drawable/ic_launcher"/>
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12dp"
            android:textStyle="bold"/>
        <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="10dp"/>
    </LinearLayout>

</LinearLayout>


To implement our custom info contents, we have to create our custom InfoWindowAdapter class. Override getInfoContents(Marker marker) to return our custom view. And call myMap.setInfoWindowAdapter(new MyInfoWindowAdapter()) to set our InfoWindowAdapter. In this exercise, we haven't handle getInfoWindow(Marker marker), simple return null.
package com.example.androidmapsv2;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity 
 implements OnMapLongClickListener{
 
 class MyInfoWindowAdapter implements InfoWindowAdapter{

        private final View myContentsView;
  
  MyInfoWindowAdapter(){
   myContentsView = getLayoutInflater().inflate(R.layout.custom_info_contents, null);
  }
  
  @Override
  public View getInfoContents(Marker marker) {
   
   TextView tvTitle = ((TextView)myContentsView.findViewById(R.id.title));
            tvTitle.setText(marker.getTitle());
            TextView tvSnippet = ((TextView)myContentsView.findViewById(R.id.snippet));
            tvSnippet.setText(marker.getSnippet());
   
            return myContentsView;
  }

  @Override
  public View getInfoWindow(Marker marker) {
   // TODO Auto-generated method stub
   return null;
  }
  
 }

 final int RQS_GooglePlayServices = 1;
 GoogleMap myMap;
 TextView tvLocInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvLocInfo = (TextView)findViewById(R.id.locinfo);
        
        FragmentManager myFragmentManager = getFragmentManager();
        MapFragment myMapFragment 
         = (MapFragment)myFragmentManager.findFragmentById(R.id.map);
        myMap = myMapFragment.getMap();
        
        myMap.setMyLocationEnabled(true);

        //myMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        //myMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        //myMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
        myMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
        
        myMap.getUiSettings().setZoomControlsEnabled(true);
        myMap.getUiSettings().setCompassEnabled(true);
        myMap.getUiSettings().setMyLocationButtonEnabled(true);
        
        myMap.getUiSettings().setRotateGesturesEnabled(true);
        myMap.getUiSettings().setScrollGesturesEnabled(true);
        myMap.getUiSettings().setTiltGesturesEnabled(true);
        myMap.getUiSettings().setZoomGesturesEnabled(true);
        //or myMap.getUiSettings().setAllGesturesEnabled(true);
        
        myMap.setTrafficEnabled(true);
        
        myMap.setOnMapLongClickListener(this);
        
        myMap.setInfoWindowAdapter(new MyInfoWindowAdapter());

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
  case R.id.menu_legalnotices:
   String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
     getApplicationContext());
   AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
   LicenseDialog.setTitle("Legal Notices");
   LicenseDialog.setMessage(LicenseInfo);
   LicenseDialog.show();
   return true; 
  }
  return super.onOptionsItemSelected(item);
 }

 @Override
 protected void onResume() {

  super.onResume();
  
  int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
  
  if (resultCode == ConnectionResult.SUCCESS){
   Toast.makeText(getApplicationContext(), 
     "isGooglePlayServicesAvailable SUCCESS", 
     Toast.LENGTH_LONG).show(); 
  }else{
   GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices); 
  }
 }

 @Override
 public void onMapLongClick(LatLng point) {
  tvLocInfo.setText("New marker added@" + point.toString());

  Marker newMarker = myMap.addMarker(new MarkerOptions()
        .position(point)
        .snippet(point.toString()));
  
  newMarker.setTitle(newMarker.getId());

 }
    
}

As a exercise, you can try to return null in getInfoContents(Marker marker), and return the custom view in getInfoWindow(Marker marker) to check the result.


download filesDownload the files.

Next:
- Implement Custom InfoWindowAdapter with dynamic icon
- Detect Info Window Click, implements OnInfoWindowClickListener


The series:
A simple example using Google Maps Android API v2, step by step.

6 comments:

uTehn said...

Sir ,How to change an info image dynamically.

Andr.oid Eric said...

hello uTehn,

Please read Custom InfoWindowAdapter with dynamic icon.

Rakesh Gondaliya said...

Hello,

How can I pass custom Overlay to map...

Prashanthi Shivapooja said...

Does anyone have idea of shapefile import and edit in google maps. Please send me mail if u have code its urgent shivapooja@gmail.com.

Samuele said...

Hi, i try to execute the exempt on my nexus 7 with android 4.4.4 and give me this error: android.view.InflateException: Binary XML file Line #12: Error inflating class fragment

I think is in activityMain.xml file but i don't really know what it can be.

I run another application using googlemapsV2 and it working good.

Can you help me?!
Many thanks.

Anonymous said...

hello sir..its working fine but i want to display title as a text only on some marker..and for some marker i want to display text with image..i add adepter different for them but still it display text with image for all marker