How to Implement draggable map like uber android, Update with change location -
how implement draggable map uber? using google maps v2. got solution referring this post , sharing complete solution here
updated latest code included change location autocomplete
complete project can found here
logic simple need framelayout
, add map , marker layout inside framelayout
make maker layout gravity center , latitude , longitude of centre point of map on camera change refer this answer here code create activity_maps.xml
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:orientation="vertical"> <linearlayout android:id="@+id/container_toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <include android:id="@+id/toolbar" layout="@layout/toolbar" /> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginleft="5dp" android:layout_marginright="5dp" android:layout_margintop="5dp" android:orientation="vertical"> <textview android:gravity="center_vertical" android:id="@+id/locality" android:layout_width="match_parent" android:layout_height="wrap_content" android:drawableleft="@drawable/ic_btn_current_location" android:drawablepadding="@dimen/list_row_padding" android:ellipsize="end" android:padding="10dp" android:singleline="true" android:text="click change location" android:textsize="@dimen/font_22" /> <edittext android:id="@+id/address" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margintop="5dp" android:ellipsize="end" android:enabled="false" android:hint="address" android:singleline="true" /> </linearlayout> </linearlayout> <framelayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/container_toolbar"> <fragment xmlns:tools="http://schemas.android.com/tools" 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.sample.sishin.maplocation.mapsactivity" /> <linearlayout android:id="@+id/locationmarker" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginbottom="30dp" android:gravity="center" android:orientation="vertical" > <textview android:id="@+id/locationmarkertext" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/rounded_corner_map" android:gravity="center" android:minwidth="250dp" android:paddingleft="2dp" android:paddingright="2dp" android:text=" set location " android:textcolor="@android:color/white" /> <imageview android:id="@+id/imagemarker" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/add_marker" /> </linearlayout> </framelayout>
create textview
backgound xml here rounded_corner_map.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <solid android:color="#000000" /> <stroke android:width="2dp" android:color="#ffffff" /> <padding android:bottom="8dp" android:left="1dp" android:right="1dp" android:top="8dp" /> <corners android:bottomleftradius="15dp" android:bottomrightradius="15dp" android:topleftradius="15dp" android:toprightradius="15dp" /> </shape>
and here activity class mainactivity.java
package com.sample.sishin.maplocation; import android.manifest; import android.app.alertdialog; import android.content.context; import android.content.dialoginterface; import android.content.intent; import android.content.pm.packagemanager; import android.location.location; import android.os.handler; import android.os.resultreceiver; import android.provider.settings; import android.support.v4.app.activitycompat; import android.os.bundle; import android.support.v7.app.appcompatactivity; import android.support.v7.widget.toolbar; import android.util.log; import android.view.view; import android.widget.edittext; import android.widget.textview; import android.widget.toast; import com.google.android.gms.common.connectionresult; import com.google.android.gms.common.googleapiavailability; import com.google.android.gms.common.googleplayservicesnotavailableexception; import com.google.android.gms.common.googleplayservicesrepairableexception; import com.google.android.gms.common.googleplayservicesutil; import com.google.android.gms.common.api.googleapiclient; import com.google.android.gms.common.api.status; import com.google.android.gms.location.locationrequest; import com.google.android.gms.location.locationservices; import com.google.android.gms.location.places.place; import com.google.android.gms.location.places.ui.placeautocomplete; import com.google.android.gms.maps.cameraupdatefactory; import com.google.android.gms.maps.googlemap; import com.google.android.gms.maps.onmapreadycallback; import com.google.android.gms.maps.supportmapfragment; import com.google.android.gms.maps.model.cameraposition; import com.google.android.gms.maps.model.latlng; public class mapsactivity extends appcompatactivity implements onmapreadycallback, googleapiclient.connectioncallbacks, googleapiclient.onconnectionfailedlistener, com.google.android.gms.location.locationlistener { private googlemap mmap; private googleapiclient mgoogleapiclient; private final static int play_services_resolution_request = 9000; private static string tag = "map location"; context mcontext; textview mlocationmarkertext; private latlng mcenterlatlong; /** * receiver registered activity response fetchaddressintentservice. */ private addressresultreceiver mresultreceiver; /** * formatted location address. */ protected string maddressoutput; protected string mareaoutput; protected string mcityoutput; protected string mstateoutput; edittext mlocationaddress; textview mlocationtext; private static final int request_code_autocomplete = 1; toolbar mtoolbar; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_maps); mcontext = this; // obtain supportmapfragment , notified when map ready used. supportmapfragment mapfragment = (supportmapfragment) getsupportfragmentmanager() .findfragmentbyid(r.id.map); mlocationmarkertext = (textview) findviewbyid(r.id.locationmarkertext); mlocationaddress = (edittext) findviewbyid(r.id.address); mlocationtext = (textview) findviewbyid(r.id.locality); mtoolbar = (toolbar) findviewbyid(r.id.toolbar); setsupportactionbar(mtoolbar); getsupportactionbar().setdisplayshowhomeenabled(true); getsupportactionbar().settitle(getresources().getstring(r.string.app_name)); mlocationtext.setonclicklistener(new view.onclicklistener() { @override public void onclick(view view) { openautocompleteactivity(); } }); mapfragment.getmapasync(this); mresultreceiver = new addressresultreceiver(new handler()); if (checkplayservices()) { // if check succeeds, proceed normal processing. // otherwise, prompt user valid play services apk. if (!apputils.islocationenabled(mcontext)) { // notify user alertdialog.builder dialog = new alertdialog.builder(mcontext); dialog.setmessage("location not enabled!"); dialog.setpositivebutton("open location settings", new dialoginterface.onclicklistener() { @override public void onclick(dialoginterface paramdialoginterface, int paramint) { intent myintent = new intent(settings.action_location_source_settings); startactivity(myintent); } }); dialog.setnegativebutton("cancel", new dialoginterface.onclicklistener() { @override public void onclick(dialoginterface paramdialoginterface, int paramint) { // todo auto-generated method stub } }); dialog.show(); } buildgoogleapiclient(); } else { toast.maketext(mcontext, "location not supported in device", toast.length_short).show(); } } /** * manipulates map once available. * callback triggered when map ready used. * can add markers or lines, add listeners or move camera. in case, * add marker near sydney, australia. * if google play services not installed on device, user prompted install * inside supportmapfragment. method triggered once user has * installed google play services , returned app. */ @override public void onmapready(googlemap googlemap) { log.d(tag, "onmapready"); mmap = googlemap; mmap.setoncamerachangelistener(new googlemap.oncamerachangelistener() { @override public void oncamerachange(cameraposition cameraposition) { log.d("camera postion change" + "", cameraposition + ""); mcenterlatlong = cameraposition.target; mmap.clear(); try { location mlocation = new location(""); mlocation.setlatitude(mcenterlatlong.latitude); mlocation.setlongitude(mcenterlatlong.longitude); startintentservice(mlocation); mlocationmarkertext.settext("lat : " + mcenterlatlong.latitude + "," + "long : " + mcenterlatlong.longitude); } catch (exception e) { e.printstacktrace(); } } }); if (activitycompat.checkselfpermission(this, manifest.permission.access_fine_location) != packagemanager.permission_granted && activitycompat.checkselfpermission(this, manifest.permission.access_coarse_location) != packagemanager.permission_granted) { // todo: consider calling // activitycompat#requestpermissions // here request missing permissions, , overriding // public void onrequestpermissionsresult(int requestcode, string[] permissions, // int[] grantresults) // handle case user grants permission. see documentation // activitycompat#requestpermissions more details. return; } // mmap.setmylocationenabled(true); // mmap.getuisettings().setmylocationbuttonenabled(true); // // // add marker in sydney , move camera // latlng sydney = new latlng(-34, 151); // mmap.addmarker(new markeroptions().position(sydney).title("marker in sydney")); // mmap.movecamera(cameraupdatefactory.newlatlng(sydney)); } @override public void onconnected(bundle bundle) { if (activitycompat.checkselfpermission(this, manifest.permission.access_fine_location) != packagemanager.permission_granted && activitycompat.checkselfpermission(this, manifest.permission.access_coarse_location) != packagemanager.permission_granted) { // todo: consider calling // activitycompat#requestpermissions // here request missing permissions, , overriding // public void onrequestpermissionsresult(int requestcode, string[] permissions, // int[] grantresults) // handle case user grants permission. see documentation // activitycompat#requestpermissions more details. return; } location mlastlocation = locationservices.fusedlocationapi.getlastlocation( mgoogleapiclient); if (mlastlocation != null) { changemap(mlastlocation); log.d(tag, "on connected"); } else try { locationservices.fusedlocationapi.removelocationupdates( mgoogleapiclient, this); } catch (exception e) { e.printstacktrace(); } try { locationrequest mlocationrequest = new locationrequest(); mlocationrequest.setinterval(10000); mlocationrequest.setfastestinterval(5000); mlocationrequest.setpriority(locationrequest.priority_high_accuracy); locationservices.fusedlocationapi.requestlocationupdates( mgoogleapiclient, mlocationrequest, this); } catch (exception e) { e.printstacktrace(); } } @override public void onconnectionsuspended(int i) { log.i(tag, "connection suspended"); mgoogleapiclient.connect(); } @override public void onlocationchanged(location location) { try { if (location != null) changemap(location); locationservices.fusedlocationapi.removelocationupdates( mgoogleapiclient, this); } catch (exception e) { e.printstacktrace(); } } @override public void onconnectionfailed(connectionresult connectionresult) { } protected synchronized void buildgoogleapiclient() { mgoogleapiclient = new googleapiclient.builder(this) .addconnectioncallbacks(this) .addonconnectionfailedlistener(this) .addapi(locationservices.api) .build(); } @override protected void onstart() { super.onstart(); try { mgoogleapiclient.connect(); } catch (exception e) { e.printstacktrace(); } } @override protected void onstop() { super.onstop(); try { } catch (runtimeexception e) { e.printstacktrace(); } if (mgoogleapiclient != null && mgoogleapiclient.isconnected()) { mgoogleapiclient.disconnect(); } } private boolean checkplayservices() { int resultcode = googleplayservicesutil.isgoogleplayservicesavailable(this); if (resultcode != connectionresult.success) { if (googleplayservicesutil.isuserrecoverableerror(resultcode)) { googleplayservicesutil.geterrordialog(resultcode, this, play_services_resolution_request).show(); } else { //finish(); } return false; } return true; } private void changemap(location location) { log.d(tag, "reaching map" + mmap); if (activitycompat.checkselfpermission(this, manifest.permission.access_fine_location) != packagemanager.permission_granted && activitycompat.checkselfpermission(this, manifest.permission.access_coarse_location) != packagemanager.permission_granted) { // todo: consider calling // activitycompat#requestpermissions // here request missing permissions, , overriding // public void onrequestpermissionsresult(int requestcode, string[] permissions, // int[] grantresults) // handle case user grants permission. see documentation // activitycompat#requestpermissions more details. return; } // check if map created or not if (mmap != null) { mmap.getuisettings().setzoomcontrolsenabled(false); latlng latlong; latlong = new latlng(location.getlatitude(), location.getlongitude()); cameraposition cameraposition = new cameraposition.builder() .target(latlong).zoom(19f).tilt(70).build(); mmap.setmylocationenabled(true); mmap.getuisettings().setmylocationbuttonenabled(true); mmap.animatecamera(cameraupdatefactory .newcameraposition(cameraposition)); mlocationmarkertext.settext("lat : " + location.getlatitude() + "," + "long : " + location.getlongitude()); startintentservice(location); } else { toast.maketext(getapplicationcontext(), "sorry! unable create maps", toast.length_short) .show(); } } /** * receiver data sent fetchaddressintentservice. */ class addressresultreceiver extends resultreceiver { public addressresultreceiver(handler handler) { super(handler); } /** * receives data sent fetchaddressintentservice , updates ui in mainactivity. */ @override protected void onreceiveresult(int resultcode, bundle resultdata) { // display address string or error message sent intent service. maddressoutput = resultdata.getstring(apputils.locationconstants.result_data_key); mareaoutput = resultdata.getstring(apputils.locationconstants.location_data_area); mcityoutput = resultdata.getstring(apputils.locationconstants.location_data_city); mstateoutput = resultdata.getstring(apputils.locationconstants.location_data_street); displayaddressoutput(); // show toast message if address found. if (resultcode == apputils.locationconstants.success_result) { // showtoast(getstring(r.string.address_found)); } } } /** * updates address in ui. */ protected void displayaddressoutput() { // mlocationaddresstextview.settext(maddressoutput); try { if (mareaoutput != null) // mlocationtext.settext(mareaoutput+ ""); mlocationaddress.settext(maddressoutput); //mlocationtext.settext(mareaoutput); } catch (exception e) { e.printstacktrace(); } } /** * creates intent, adds location data extra, , starts intent service * fetching address. */ protected void startintentservice(location mlocation) { // create intent passing intent service responsible fetching address. intent intent = new intent(this, fetchaddressintentservice.class); // pass result receiver service. intent.putextra(apputils.locationconstants.receiver, mresultreceiver); // pass location data service. intent.putextra(apputils.locationconstants.location_data_extra, mlocation); // start service. if service isn't running, instantiated , started // (creating process if needed); if running remains running. // service kills automatically once intents processed. startservice(intent); } private void openautocompleteactivity() { try { // autocomplete activity requires google play services available. intent // builder checks , throws exception if not case. intent intent = new placeautocomplete.intentbuilder(placeautocomplete.mode_fullscreen) .build(this); startactivityforresult(intent, request_code_autocomplete); } catch (googleplayservicesrepairableexception e) { // indicates google play services either not installed or not date. prompt // user correct issue. googleapiavailability.getinstance().geterrordialog(this, e.getconnectionstatuscode(), 0 /* requestcode */).show(); } catch (googleplayservicesnotavailableexception e) { // indicates google play services not available , problem not // resolvable. string message = "google play services not available: " + googleapiavailability.getinstance().geterrorstring(e.errorcode); toast.maketext(mcontext, message, toast.length_short).show(); } } /** * called after autocomplete activity has finished return result. */ @override public void onactivityresult(int requestcode, int resultcode, intent data) { super.onactivityresult(requestcode, resultcode, data); // check result autocomplete widget. if (requestcode == request_code_autocomplete) { if (resultcode == result_ok) { // user's selected place intent. place place = placeautocomplete.getplace(mcontext, data); // todo call location based filter latlng latlong; latlong = place.getlatlng(); //mlocationtext.settext(place.getname() + ""); cameraposition cameraposition = new cameraposition.builder() .target(latlong).zoom(19f).tilt(70).build(); if (activitycompat.checkselfpermission(this, manifest.permission.access_fine_location) != packagemanager.permission_granted && activitycompat.checkselfpermission(this, manifest.permission.access_coarse_location) != packagemanager.permission_granted) { // todo: consider calling // activitycompat#requestpermissions // here request missing permissions, , overriding // public void onrequestpermissionsresult(int requestcode, string[] permissions, // int[] grantresults) // handle case user grants permission. see documentation // activitycompat#requestpermissions more details. return; } mmap.setmylocationenabled(true); mmap.animatecamera(cameraupdatefactory .newcameraposition(cameraposition)); } } else if (resultcode == placeautocomplete.result_error) { status status = placeautocomplete.getstatus(mcontext, data); } else if (resultcode == result_canceled) { // indicates activity closed before selection made. example if // user pressed button. } } }
and manifest file is
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.sample.sishin.maplocation"> <!-- access_coarse/fine_location permissions not required use google maps android api v2, must specify either coarse or fine location permissions 'mylocation' functionality. --> <uses-permission android:name="android.permission.access_fine_location" /> <uses-permission android:name="android.permission.access_coarse_location" /> <application android:allowbackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsrtl="true" android:theme="@style/apptheme"> <!-- api key google maps-based apis defined string resource. (see file "res/values/google_maps_api.xml"). note api key linked encryption key used sign apk. need different api key each encryption key, including release key used sign apk publishing. can define keys debug , release targets in src/debug/ , src/release/. --> <meta-data android:name="com.google.android.geo.api_key" android:value="your key here" /> <activity android:name="com.sample.sishin.maplocation.mapsactivity" android:label="@string/title_activity_maps"> <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> <service android:name="com.sample.sishin.maplocation.fetchaddressintentservice" android:exported="false" /> </application> </manifest>
Comments
Post a Comment