Android: Drag map while keeping marker at the center
Solution 1
Having a map under an ImageView with your marker icon would be the best way to go here (just a framelayout with your map fragment under and your marker image centered on top should work). Then you can use an OnCameraIdleListener
which would receive a callback when the map movement has ended. So just set an instance of OnCameraIdleListener
to your map to listen for movement callbacks like so:
map.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
@Override
public void onCameraIdle() {
//get latlng at the center by calling
LatLng midLatLng = map.getCameraPosition().target;
}
});
Solution 2
Try at first this layout for your Activity_map.xml:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/gps"
/>
</RelativeLayout>
AIS
Updated on June 05, 2022Comments
-
AIS about 2 years
I am currently getting Current Location of device (lat,lng) in MapActivity. Now , I want to let the user move the map, while keeping the marker at the center. This means that whenever the map is moved, current location will be updated. (Right?)
I followed this How to move a map under a marker? and How to attach a flexible marker on map something like Uber and Lyft? but couldn't get my concept clear.
Activity_map.xml (Here I have added ImageView)
<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <fragment android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.MapFragment" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/gps" /> </RelativeLayout>
My MapActivity is as follows :
public class MapActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener,GoogleMap.OnInfoWindowClickListener{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map); // int x =_st.jsonArray.length(); if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkLocationPermission(); } // 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); fragmentOnMap = (FragmentOnMap)getFragmentManager().findFragmentById(R.id.fragment_bottom); getFragmentManager().beginTransaction().hide(fragmentOnMap); } @Override public void onMapReady(GoogleMap googleMap) { //Get Last Known Location and convert into Current Longitute and Latitude final LocationManager mlocManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); final Location currentGeoLocation = mlocManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); double currentLat = currentGeoLocation.getLatitude(); double currentLon = currentGeoLocation.getLongitude(); LatLng currentLatLng = new LatLng(currentLat,currentLon); //Toast.makeText(this,"Cur Lat" +currentLat+"Lon"+currentLon,Toast.LENGTH_LONG).show(); // Get JSON String and Break it down into individual nodes //double x=_location.getLatitude(); //double y=_location.getLongitude(); json_string = getIntent().getExtras().getString("JSON_DTA"); LatLng latLng = null; try { int count = 0; //jsonObject = new JSONObject(json_string); jsonArray = new JSONArray(json_string); while (count < jsonArray.length()) { JSONObject JO = jsonArray.getJSONObject(count); _id = JO.getInt("id"); _doctorname = JO.getString("doctorname"); _doclat = JO.getString("latitude"); _doclong = JO.getString("longitude"); count++; Double d = Double.parseDouble(_doclat); Double e = Double.parseDouble(_doclong); latLng = new LatLng(d, e); DecimalFormat df = new DecimalFormat("####0.0"); DistanceBetweenPoints distanceBetweenPoints = new DistanceBetweenPoints(); double distance = distanceBetweenPoints.CalculationByDistance(currentLatLng,latLng); double distanceThreshHold = 7 ; if(distance < distanceThreshHold ) { mMap = googleMap; mMap.setOnInfoWindowClickListener(this); MarkerOptions _markeroptions = new MarkerOptions() .position(latLng) .title(_doctorname+": " + df.format(distance) + " KM" ) .icon(BitmapDescriptorFactory.fromResource(R.drawable.smallest_logo)); mMap.addMarker(_markeroptions); mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); } else { mMap = googleMap; } } } catch (JSONException e) { e.printStackTrace(); } //Initialize Google Play Services if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { buildGoogleApiClient(); mMap.setMyLocationEnabled(true); } } else { buildGoogleApiClient(); mMap.setMyLocationEnabled(true); } } protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); mGoogleApiClient.connect(); } @Override public void onConnected(@Nullable Bundle bundle) { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(1000); mLocationRequest.setFastestInterval(1000); mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); } } @Override public void onConnectionSuspended(int i) { } @Override public void onLocationChanged(Location location) { mLastLocation = location; if (mCurrLocationMarker != null) { mCurrLocationMarker.remove(); } //Place current location marker LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude()); MarkerOptions markerOptions = new MarkerOptions(); markerOptions.position(latLng); markerOptions.title("Current Position"); markerOptions.draggable(true); markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)); mCurrLocationMarker = mMap.addMarker(markerOptions); // Toast.makeText(this, "Current" + latLng, Toast.LENGTH_LONG).show(); String tag = null; Log.d(tag, "lon: " + location.getLongitude() + " ----- lat: " + location.getLatitude()); //move map camera mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng)); mMap.animateCamera(CameraUpdateFactory.zoomTo(11)); //stop location updates if (mGoogleApiClient != null) { LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); } } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { } public boolean checkLocationPermission(){ if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Asking user if explanation is needed if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { // Show an expanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. //Prompt the user once explanation has been shown ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION); } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION); } return false; } else { return true; } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_LOCATION: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission was granted. if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { if (mGoogleApiClient == null) { buildGoogleApiClient(); } mMap.setMyLocationEnabled(true); } } else { // Permission denied, Disable the functionality that depends on this permission. Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show(); } return; } // other 'case' lines to check for other permissions this app might request. //You can add here other case statements according to your requirement. } }
Your help will much appreciated. Thank you.
-
AIS over 7 yearsSo my ImageView will be on top of map fragment?
-
Andrii Omelchenko over 7 yearsYes, it should be on top of map fragment.
-
AIS over 7 yearsEdited...see original post
-
Joey Dalu over 7 yearsand make sure to center it
(android:layout_gravity="center")
if you're using a frame layout, else it appears at the top left. -
Andrii Omelchenko over 7 years1) remove
android:orientation="vertical"
for your rootRelativeLayout
2) removexmlns:android="http://schemas.android.com/apk/res/android"
andxmlns:tools="http://schemas.android.com/tools"
from your map fragment; 3) changeandroid:name="com.google.android.gms.maps.SupportMapFragment"
toclass="com.google.android.gms.maps.SupportMapFragment"
as provided here. It should help. -
AIS over 7 yearsNot using xmlns:android="schemas.android.com/apk/res/android"> gave an error..hence its there
-
Andrii Omelchenko over 7 yearsYou should 2) remove xmlns:android="schemas.android.com/apk/res/android" and xmlns:tools="schemas.android.com/tools" from your map fragment not from root
RelativeLayout
from rootRelativeLayout
You should remove onlyandroid:orientation="vertical"
text. -
AIS over 7 yearsOkay, now Im getting imageview on top of map...now I want this to show my current Location, just like I am showing it my MyActivity code.
-
Andrii Omelchenko over 7 years
CameraPosition center = mGoogleMap.getCameraPosition();
wheremGoogleMap
got inpublic void onMapReady(GoogleMap googleMap) { mGoogleMap = googleMap; }
-
AIS over 7 yearsAdded CameraPosition center = mGoogleMap.getCameraPosition();
-
AIS over 7 yearsSorry, added LatLng center = mMap.getCameraPosition().target; Toast.makeText(this, "Current" + center, Toast.LENGTH_LONG).show(); at the end of OnMapReady method, but got 0/0
-
AIS over 7 yearsThis has to be called in OnMapReady method?
-
AIS over 7 yearsSolved by using yours and @Joey Dalu 's answers. Can you tell me why I had to make changes in map xml layout?
-
Joey Dalu over 7 years@AIS Yes, set the
OnCameraIdleListener
after OnMapReady has been called. Or are you asking about something else? -
Naveed Ahmad about 6 yearsgetting incorrect location map.getCameraPosition().target, as my map is showing I am in pakistan and I am getting lat long of egypt
-
Muthu S about 5 yearsIn my case if i used setOnCameraIdleListener, this method keep on triggering when it is idle. I need only once after map dragged.. How to go further:-| Thanks
-
mani over 2 yearssetOnCameraIdleListener should be called in OnMapReady function.