Home > Google Maps v2 with Button clickListener on Custom infowindow

Google Maps v2 with Button clickListener on Custom infowindow

This tutorial explain how to implement Button clickListener on Custom infowindow on Google Maps v2 marker in android application.

1. Setup on Goggle Developer Console

1. Go to Goggle Developer Console https://console.developers.google.com/

After you gain access to the console you can start by creating your New project. I choose project name "googlemap"

2. After created project enable Google Maps Android API

Click on Google Maps Android API for enable api

Click on Enable button After successfuly enabled

3. Go to Credentials left hand side menu and create API Key

Press on create credential blue button & select API Key after that API key created dialog show press close button in this dialog.

4. After successfully created API Key add android application Package name (I choose package name com.androidlearningtutorials.googlemap) & SHA1

Check tutorial how to find SHA1 in Andriod Studio SHA1

Click on API Key 1

In Key restriction by default selected is None choose Android apps & Add package name and fingerprint

After added Add package name and fingerprint press on save button.

After successfully copy key & save on note pad these key use in android application.


2. Creating Android Project

1. Create a new project in Android Studio from File ? New Project and fill the project details.


2. Open build.gradle add Google Play Services 'com.google.android.gms:play-services:8.4.0' after adding click on Sync Now

									
apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.androidlearningtutorials.googlemap" minSdkVersion 15 targetSdkVersion 25 versionCode 1 versionName "1.0" multiDexEnabled true } android { packagingOptions { exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/NOTICE' exclude 'META-INF/LICENSE' } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:25.2.0' compile 'com.google.android.gms:play-services:8.4.0' }

3. Add the below permissions to AndroidManifest.xml file.

									
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androidlearningtutorials.googlemap"> <!-- need permission for google map --> <permission android:name="com.androidlearningtutorials.googlemap.permission.MAPS_RECEIVE" android:protectionLevel="signature" /> <uses-feature android:glEsVersion="0x00020000" android:required="true" /> <uses-library android:name="com.google.android.maps" /> <uses-permission android:name="com.androidlearningtutorials.googlemap.permission.MAPS_RECEIVE" /> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <!-- paste create google API Key --> <meta-data android:name="com.google.android.geo.API_KEY" android:value="AIzaSyD3S4jr6i1PSRR0N1e6ywdga75LXlCzbOg"/> </application> </manifest>

4. Now create a new class MapWrapperLayout.java in parent package add below code.

									
package com.androidlearningtutorials.googlemap; import android.content.Context; import android.graphics.Point; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.RelativeLayout; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Marker; public class MapWrapperLayout extends RelativeLayout { /** * Reference to a GoogleMap object */ private GoogleMap map; /** * Vertical offset in pixels between the bottom edge of our InfoWindow * and the marker position (by default it's bottom edge too). * It's a good idea to use custom markers and also the InfoWindow frame, * because we probably can't rely on the sizes of the default marker and frame. */ private int bottomOffsetPixels; /** * A currently selected marker */ private Marker marker; /** * Our custom view which is returned from either the InfoWindowAdapter.getInfoContents * or InfoWindowAdapter.getInfoWindow */ private View infoWindow; public MapWrapperLayout(Context context) { super(context); } public MapWrapperLayout(Context context, AttributeSet attrs) { super(context, attrs); } public MapWrapperLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Must be called before we can route the touch events */ public void init(GoogleMap map, int bottomOffsetPixels) { this.map = map; this.bottomOffsetPixels = bottomOffsetPixels; } /** * Best to be called from either the InfoWindowAdapter.getInfoContents * or InfoWindowAdapter.getInfoWindow. */ public void setMarkerWithInfoWindow(Marker marker, View infoWindow) { this.marker = marker; this.infoWindow = infoWindow; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean ret = false; // Make sure that the infoWindow is shown and we have all the needed references if (marker != null && marker.isInfoWindowShown() && map != null && infoWindow != null) { // Get a marker position on the screen Point point = map.getProjection().toScreenLocation(marker.getPosition()); // Make a copy of the MotionEvent and adjust it's location // so it is relative to the infoWindow left top corner MotionEvent copyEv = MotionEvent.obtain(ev); copyEv.offsetLocation( -point.x + (infoWindow.getWidth() / 2), -point.y + infoWindow.getHeight() + bottomOffsetPixels); // Dispatch the adjusted MotionEvent to the infoWindow ret = infoWindow.dispatchTouchEvent(copyEv); } // If the infoWindow consumed the touch event, then just return true. // Otherwise pass this event to the super class and return it's result return ret || super.dispatchTouchEvent(ev); } }

5. Now open activity_main.xml add MapFragment like as below.

									
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <com.androidlearningtutorials.googlemap.MapWrapperLayout android:id="@+id/map_relative_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/map" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.androidlearningtutorials.googlemap.MainActivity" /> </com.androidlearningtutorials.googlemap.MapWrapperLayout> </RelativeLayout>

6. Now create a new class OnInfoWindowElemTouchListener.java in parent package add below code.

									
package com.androidlearningtutorials.googlemap; import android.graphics.drawable.Drawable; import android.os.Handler; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import com.google.android.gms.maps.model.Marker; public abstract class OnInfoWindowElemTouchListener implements OnTouchListener { private final View view; private final Drawable bgDrawableNormal; private final Drawable bgDrawablePressed; private final Handler handler = new Handler(); private Marker marker; private boolean pressed = false; public OnInfoWindowElemTouchListener(View view, Drawable bgDrawableNormal, Drawable bgDrawablePressed) { this.view = view; this.bgDrawableNormal = bgDrawableNormal; this.bgDrawablePressed = bgDrawablePressed; } public void setMarker(Marker marker) { this.marker = marker; } @Override public boolean onTouch(View vv, MotionEvent event) { if (0 <= event.getX() && event.getX() <= view.getWidth() && 0 <= event.getY() && event.getY() <= view.getHeight()) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: startPress(); break; // We need to delay releasing of the view a little so it shows the pressed state on the screen case MotionEvent.ACTION_UP: handler.postDelayed(confirmClickRunnable, 150); break; case MotionEvent.ACTION_CANCEL: endPress(); break; default: break; } } else { // If the touch goes outside of the view's area // (like when moving finger out of the pressed button) // just release the press endPress(); } return false; } private void startPress() { if (!pressed) { pressed = true; handler.removeCallbacks(confirmClickRunnable); view.setBackground(bgDrawablePressed); if (marker != null) marker.showInfoWindow(); } } private boolean endPress() { if (pressed) { this.pressed = false; handler.removeCallbacks(confirmClickRunnable); view.setBackground(bgDrawableNormal); if (marker != null) marker.showInfoWindow(); return true; } else return false; } private final Runnable confirmClickRunnable = new Runnable() { public void run() { if (endPress()) { onClickConfirmed(view, marker); } } }; /** * This is called after a successful click */ protected abstract void onClickConfirmed(View v, Marker marker); }

7. Now create a custom_infowindow.xml add below code.

									
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content"> <LinearLayout android:id="@+id/toplayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:paddingTop="5dip" android:paddingLeft="10dip" android:paddingRight="20dip" android:paddingBottom="5dip"> <ImageView android:id="@+id/clientPic" android:layout_width="60dip" android:layout_height="60dip" android:src="@drawable/android" android:layout_marginLeft="8dip" android:layout_gravity="center_vertical"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_marginLeft="2dip" android:layout_gravity="center_vertical"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical"> <ImageView android:layout_width="25dip" android:layout_height="25dip" android:layout_marginLeft="5dip" android:background="@drawable/ic_company"/> <TextView android:id="@+id/nameTxt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Amixx XX Soluxxxxx" android:textSize="10dip" android:gravity="center_vertical" android:textColor="#000000"/> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical"> <ImageView android:layout_width="25dip" android:layout_height="25dip" android:layout_marginLeft="5dip" android:background="@drawable/ic_call"/> <TextView android:id="@+id/mobileTxt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="+91-98XXXXX200" android:textSize="10dip" android:gravity="center_vertical" android:textColor="#000000"/> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical"> <ImageView android:layout_width="25dip" android:layout_height="25dip" android:layout_marginLeft="5dip" android:background="@drawable/ic_location"/> <TextView android:id="@+id/addressTxt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="android@gmail.com" android:textSize="10dip" android:gravity="center_vertical" android:textColor="#000000"/> </LinearLayout> </LinearLayout> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_below="@+id/toplayout"> <Button android:id="@+id/btnOne" android:layout_width="120dip" android:layout_height="40dip" android:text="one btn" android:background="@drawable/btn_bg"/> <Button android:id="@+id/btnTwo" android:layout_width="120dip" android:layout_height="40dip" android:text="two btn" android:layout_marginLeft="10dip" android:background="@drawable/btn_bg"/> </LinearLayout> </RelativeLayout>

8. Now open MainActivity.java and add the below code.

								
package com.androidlearningtutorials.googlemap; import android.content.Context; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; public class MainActivity extends AppCompatActivity { private ViewGroup infoWindow; private TextView infoTitle; private TextView infoSnippet; private Button infoButton1, infoButton2; private OnInfoWindowElemTouchListener infoButtonListener; static final LatLng latlng1 = new LatLng(28.5355, 77.3910); static final LatLng latlng2 = new LatLng(28.6208768, 77.3726377); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final SupportMapFragment mapFragment = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map); final MapWrapperLayout mapWrapperLayout = (MapWrapperLayout)findViewById(R.id.map_relative_layout); final GoogleMap googleMap = mapFragment.getMap(); // MapWrapperLayout initialization // 39 - default marker height // 20 - offset between the default InfoWindow bottom edge and it's content bottom edge mapWrapperLayout.init(googleMap, getPixelsFromDp(this, 39 + 20)); // We want to reuse the info window for all the markers, // so let's create only one class member instance this.infoWindow = (ViewGroup)getLayoutInflater().inflate(R.layout.custom_infowindow, null); this.infoTitle = (TextView)infoWindow.findViewById(R.id.nameTxt); this.infoSnippet = (TextView)infoWindow.findViewById(R.id.addressTxt); this.infoButton1 = (Button)infoWindow.findViewById(R.id.btnOne); this.infoButton2 = (Button)infoWindow.findViewById(R.id.btnTwo); // Setting custom OnTouchListener which deals with the pressed state // so it shows up this.infoButtonListener = new OnInfoWindowElemTouchListener(infoButton1, getResources().getDrawable(R.drawable.btn_bg), getResources().getDrawable(R.drawable.btn_bg)){ @Override protected void onClickConfirmed(View v, Marker marker) { // Here we can perform some action triggered after clicking the button Toast.makeText(MainActivity.this, "click on button 1", Toast.LENGTH_SHORT).show(); } }; this.infoButton1.setOnTouchListener(infoButtonListener); infoButtonListener = new OnInfoWindowElemTouchListener(infoButton2, getResources().getDrawable(R.drawable.btn_bg),getResources().getDrawable(R.drawable.btn_bg)){ @Override protected void onClickConfirmed(View v, Marker marker) { Toast.makeText(getApplicationContext(), "click on button 2", Toast.LENGTH_LONG).show(); } }; infoButton2.setOnTouchListener(infoButtonListener); /*infoWindow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getApplicationContext(), "click on infowindow", Toast.LENGTH_LONG).show(); } });*/ googleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() { @Override public View getInfoWindow(Marker marker) { return null; } @Override public View getInfoContents(Marker marker) { // Setting up the infoWindow with current's marker info infoSnippet.setText(marker.getTitle()); infoTitle.setText(marker.getSnippet()); infoButtonListener.setMarker(marker); // We must call this to set the current marker and infoWindow references // to the MapWrapperLayout mapWrapperLayout.setMarkerWithInfoWindow(marker, infoWindow); return infoWindow; } }); // Let's add a couple of markers googleMap.addMarker(new MarkerOptions() .position(latlng1) .title("Source") .snippet("Comapny Name") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN))); googleMap.addMarker(new MarkerOptions() .position(latlng2) .title("Destination") .snippet("AmisunXXXXXX") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE))); //googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, 15)); googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latlng1, 10)); } public static int getPixelsFromDp(Context context, float dp) { final float scale = context.getResources().getDisplayMetrics().density; return (int)(dp * scale + 0.5f); } }

9. Run your application Output as below.



Dheerendra Singh

Dheerendra Singh is a Mobile Developer(Android) & Web Developer(PHP) of Amisun IT Solutions, Master degree in Computer Science.


About Us

Amisun IT Solutions is an expert Software Development Company giving complete IT arrangements and going about as a seaward improvement community for abroad advancement firms.

We are an imaginative organization, situated in India that gives a progression of Web-based programming applications that have helped clients make fruitful online activities.

Our group of forward masterminds and reforming individuals tries to furnish you with the best of arrangements with flawlessness second to none. Our key concentration is dependably to furnish you with solid arrangements which are precisely planned and planned with stringent quality principles. ...   

Read more

Address

Shoppers Square Mall Shop No. 17 & 18, First Floor,
Shoppers Square Mall, Budhh Prakash Garg Marg, Block 14, Sector 10,
Raj Nagar, Ghaziabad, Uttar Pradesh 201002
P: (+91) 9899776200, (+91) 9899773200