How would I go through moving a marker on a Map Activity without having to long click and hold that marker until it receives focus?
I just want to touch and drag, but it takes around 1-2 secs before it receives focus and fires drag event.
here's my code:
mMap = googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
Marker marker = mMap.addMarker(new MarkerOptions()
.position(latLng)
.draggable(true));
markers.add(marker);
updateUI();
}
});
mMap.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener() {
#Override
public void onMarkerDragStart(Marker marker) {
updateUI();
}
#Override
public void onMarkerDrag(Marker marker) {
updateUI();
}
#Override
public void onMarkerDragEnd(Marker marker) {
updateUI();
}
});
Related
So I've made a MapActivity which shows a MapBox map.
Then I load in all my markers(pins, which are eventually Point objects with longitude and latitude) from the database into a List< Features > markerCoordinates. markerCoordinates is then given through GeoJsonSource().
Now all my markers are displayed on the map.
Now I can't figure out how to make a marker clickable, and when clicked I need to obtain the ID of the marker so I can later on redirect to another Activity and then load in all data based on that ID. This ID of the pin needs to be the same as the ID from the database.
Mapbox Documentation doesn't really helped me out with this problem.
Does any one know how to implement this?
MapActivity.java
public class MapActivity extends AppCompatActivity {
private MapView mapView;
DatabaseHelper myDb;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_moments:
Intent intent = new Intent(MapActivity.this, MapActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivity(intent);
break;
case R.id.navigation_addmoment:
Intent intent2 = new Intent(MapActivity.this, AddMomentActivity.class);
intent2.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivity(intent2);
break;
}
return false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myDb = new DatabaseHelper(this);
Mapbox.getInstance(this, "pk.eyJ1IjoiaGlqYWNrbWFuaWFjIiwiYSI6ImNqdWlyb3E3NzE5bjc0Zm9lOHpta3AzajMifQ.ithKXW2RvhRzlPqXWBexyg");
setContentView(R.layout.activity_map);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(#NonNull MapboxMap mapboxMap) {
mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {
#Override
public void onStyleLoaded(#NonNull Style style) {
// Importing markers from database
List<Feature> markerCoordinates = new ArrayList<>();
loadPins(markerCoordinates);
// Adding markers on the map
style.addSource(new GeoJsonSource("source-id",
FeatureCollection.fromFeatures(markerCoordinates)));
// Some styling below
style.addImage("marker-icon-id",
BitmapFactory.decodeResource(
MapActivity.this.getResources(), R.drawable.mapbox_marker_icon_default));
SymbolLayer symbolLayer = new SymbolLayer("layer-id", "source-id");
symbolLayer.withProperties(
PropertyFactory.iconImage("marker-icon-id")
);
style.addLayer(symbolLayer);
}
});
}
});
}
// Switch from map to moments
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.header_items, menu);
final MenuItem listItem = menu.findItem(R.id.list_menu);
listItem.setVisible(true);
listItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
Intent intent = new Intent(MapActivity.this, MomentsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivity(intent);
return true;
}
});
return true;
}
// Reading the Database, appending each row to allMarkers
public void loadPins(List<Feature> allMarkers) {
Cursor res = myDb.getAllData();
if(res.getCount() == 0) {
// Error message
return;
}
while(res.moveToNext()) {
double longitude = Double.parseDouble(res.getString(4));
double latitude = Double.parseDouble(res.getString(5));
if(longitude == 0 || latitude == 0) {
continue;
} else {
allMarkers.add(Feature.fromGeometry(
Point.fromLngLat(
longitude,
latitude
)
));
}
}
}
#Override
public void onStart() {
super.onStart();
mapView.onStart();
}
#Override
public void onResume() {
super.onResume();
mapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mapView.onPause();
}
#Override
public void onStop() {
super.onStop();
mapView.onStop();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
#Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}
First, you should implement the onMapClick or onMapLongClick methods, so that you can handle all map clicks and retrieve the data you need.
The steps to get the marker Id on every click are roughly these:
Check whether the click was on a marker or elsewhere.
You can do this by querying the source layer (your GeoJsonSource) and checking whether there is a feature nearby the clicked spot.
If a feature was found, get the property you need.
You could use feature.getProperties() to get all the properties or feature.getStringProperty("name_of_the_property") to get a specific one. See more here.
Check this example to see how to implement all of this.
I've been trying to show some info whith info windows -in my app which uses google map- with InfoWindowAdapter but it just does'nt show any pictures so whats the problem?
here's my code for it
public class findonmap extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
Bundle recevier=getIntent().getExtras();
float a=recevier.getFloat("x");
float b=recevier.getFloat("y");
LatLng mycordinate = new LatLng(a,b);
mMap.addMarker(new MarkerOptions().position(mycordinate).icon(BitmapDescriptorFactory.
fromResource(R.drawable.marker2)));
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
// ConstraintLayout layout=(ConstraintLayout)findViewById(R.id.indo)
View view=getLayoutInflater().inflate(R.layout.info,null);
return view;
}
});
int zoomLevel = 4; //This goes up to 21
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mycordinate, zoomLevel));
}}
I can't resolve this problem. I trying to create Fragment with a map and I have this done. When I add static Long, Lat value the map show this o a map, But when I trying to make it automatic with getting localization in runnable the application just open the map and don't show specific LongLand values.
How to do this?
For getting long and late I'm using LocalizationManager, of course, I add permissions in manifest and also check runtime
public class LocalizationFragment extends Fragment implements OnMapReadyCallback {
private GoogleMap map;
MapView mapView;
View mview;
private double latitude, longtitude;
private Handler handler;
private Runnable runnable;
public LocalizationFragment() {
// Required empty public constructor
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mview = inflater.inflate(R.layout.fragment_localization, container, false);
handler = new Handler();
getLocation();
if (ContextCompat.checkSelfPermission(getContext(), android.Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 13);
}
if (ContextCompat.checkSelfPermission(getContext(), android.Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 11);
}
return mview;
}
#OnClick(R.id.button)
public void buttonStart() {
getLocation();
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mapView = (MapView) mview.findViewById(R.id.mapView);
if (mapView != null) {
mapView.onCreate(null);
mapView.onResume();
mapView.getMapAsync(this);
}
}
private void getLocation() {
LocationManager locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
latitude = location.getLatitude();
longtitude = location.getLongitude();
}
};
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission
(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
#Override
public void onMapReady(final GoogleMap googleMap) {
MapsInitializer.initialize(getContext());
map = googleMap;
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
runnable = new Runnable() {
#Override
public void run() {
getLocation();
googleMap.addMarker(new MarkerOptions().position(new LatLng(latitude, longtitude)).title("Statue").snippet("Something"));
CameraPosition liberty = CameraPosition.builder().target(new LatLng(latitude, longtitude)).zoom(15).bearing(0).tilt(45).build();
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(liberty));
handler.postDelayed(this, 5000);
}
};
}
}
You need to add markers form the main thread.add this to your runnable.
runOnUiThread(new Runnable() {
#Override
public void run() {
googleMap.addMarker(new MarkerOptions().position(new LatLng(latitude, longtitude)).title("Statue").snippet("Something"));
}
});
I think this problem come from synchronize data. If you got location after add marker, it is meaningless, you get no location, and you have no marker on map, try to move action add marker into onLocationChanged
A tab within my view pager contains a map view is showing some unexpected behaviour. For some reason whenever I go to a different tab and return to the map view tab, all 4 pins within my map view appear when only 2 of them are supposed to appear. Does anyone know why this has happened? What can be done in order to prevent this from happening?
Stage 1 (flicked the top switch)
Stage 2 (flicked the bottom switch)
Stage 3 (switching to a different tab, then returning back to the map tab)
Java class
public class FragmentCentralPark extends android.support.v4.app.Fragment implements OnMapReadyCallback {
public FragmentCentralPark() {
// Required empty constructor
}
GoogleMap mGoogleMap;
MapView mMapView;
SwitchCompat swt0;
SwitchCompat swt1;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_centralpark, container, false);
mMapView = (MapView) v.findViewById(R.id.map_centralpark);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(this); //this is important
swt0 = (SwitchCompat) v.findViewById(R.id.switch0_map_centralpark);
swt1 = (SwitchCompat) v.findViewById(R.id.switch1_map_centralpark);
return v;
}
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.getUiSettings().setZoomControlsEnabled(true);
mGoogleMap.setBuildingsEnabled(true);
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
swt0.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
initMap0(isChecked);
}
});
swt1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
initMap1(isChecked);
}
});
initMap0(swt0.isChecked());
initMap1(swt1.isChecked());
// Add markers and move the camera
LatLng centralpark_museum1 = new LatLng(40.785407, -73.957145);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_museum1)
);
LatLng centralpark_museum2 = new LatLng(40.782993, -73.958985);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_museum2)
);
// Updates the location and zoom level of the MapView
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(40.780437, -73.981063), 16);
mGoogleMap.animateCamera(cameraUpdate);
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mMapView.onSaveInstanceState(outState);
}
#Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
private void initMap0(boolean isChecked){
if (isChecked) {
mGoogleMap.setMapStyle(new MapStyleOptions(getResources()
.getString(R.string.style_json)));
} else {
mGoogleMap.setMapStyle(null);
}
}
private void initMap1(boolean isChecked){
if (isChecked) {
mGoogleMap.clear();
// Add markers and move the camera
LatLng centralpark__theatre1 = new LatLng(40.780287, -73.968832);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_theatre1)
);
LatLng centralpark__theatre2 = new LatLng(40.780437, -73.981063);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_theatre2)
);
// Updates the location and zoom level of the MapView
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(40.780437, -73.981063), 16);
mGoogleMap.animateCamera(cameraUpdate);
} else {
mGoogleMap.clear();
// Add markers and move the camera
LatLng centralpark_museum1 = new LatLng(40.785407, -73.957145);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_museum1)
);
LatLng centralpark_museum2 = new LatLng(40.782993, -73.958985);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_museum2)
);
// Updates the location and zoom level of the MapView
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(40.780437, -73.981063), 16);
mGoogleMap.animateCamera(cameraUpdate);
}
}
}
I am having issues with GoogleMap due to the fact that it gets the map asynchronously using MapView#getMapAsync.
I am experiencing a NullPointerException due to the #getMapAsync not returning in time when my Activity is passing markers to the GoogleMap object.
Can this be done synchronously or is there a better solution? Adding it to the fragment bundle would not work for me as the activity may pass the fragment markers after the #commit()
GoogleMapsFragment
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// inflate and return the layout
View v = inflater.inflate(R.layout.fragment_google_map, container,
false);
ButterKnife.bind(this, v);
mMapView.onCreate(savedInstanceState);
mMapView.onResume();// needed to get the map to display immediately
try {
MapsInitializer.initialize(getActivity().getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
Bundle bundle = getArguments();
if(bundle != null){
initialMarkers = bundle.getParcelableArrayList("markers");
}
mMapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
if (mCameraPos != null) {
mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(mCameraPos));
mCameraPos = null;
} else {
//Set default camera position over the United States.
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(new LatLng(37.09024, -95.712891)).zoom(3).build();
mGoogleMap.moveCamera(CameraUpdateFactory
.newCameraPosition(cameraPosition));
}
}
});
return v;
}
Activity
#OnClick(R.id.loadListOrMapButton)
public void onClickChangeView() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (mLocationListViewFrag.isVisible()) {
if (mGoogleMapFrag == null) {
mGoogleMapFrag = new GoogleMapFragment();
fragmentTransaction.add(R.id.fragment_container, mGoogleMapFrag);
}
bListMapButton.setText(getString(R.string.list));
fragmentTransaction.hide(mLocationListViewFrag).show(mGoogleMapFrag);
} else {
bListMapButton.setText(getString(R.string.map));
fragmentTransaction.hide(mGoogleMapFrag).show(mLocationListViewFrag);
}
fragmentTransaction.commit();
fragmentManager.executePendingTransactions();
updateDisplay();
}
UpdateDisplay
public void updateDisplay() {
if (mLocationListViewFrag != null && mLocationListViewFrag.isVisible()) {
Log.d(TAG, "Update Tax Location ListView");
mLocationListViewFrag.setLocations(mLocations);
} else if (mGoogleMapFrag != null && mGoogleMapFrag.isVisible()) {
Log.d(TAG, "Update Google Maps Markers");
//Convert locations to markers to display.
mGoogleMapFrag.clearMarkers();
for (LocationObj aLocation : mLocations) {
mGoogleMapFrag.addMarker(new MarkerOptions().position(
new LatLng(Double.valueOf(aLocation.getLat()), Double.valueOf(aLocation.getLng()))).title(aLocation.getName()));
mGoogleMapFrag.fitBounds();
}
}
}
You should move the code that handles the markers to be within the OnMapReadyCallback (https://developers.google.com/android/reference/com/google/android/gms/maps/OnMapReadyCallback) that you pass to #getMapAsync(OnMapReadyCallback callback). This will ensure the markers aren't placed until the map is available.
EDIT for additional info
Ultimately you have to solve the problem of "what do I do if someone makes #onClickChangeView get called when the map isn't ready?" From a user experience perspective, the loadListOrMapButton shouldn't even be shown until the map finishes loading. You should disable the button by default, then make this button available from within your OnMapReadyCallback. You could either grey out the button (google for "android disable button" for examples) or you could actually hide/show it with View#setVisibility.
Non-recommended approach
Although I'm hesitant to suggest it, you could instead just check if the GoogleMap is ready: from within your OnMapReadyCallback set a boolean that your outside activity can check. Something like
private boolean mapIsReady = false;
mMapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
// your normal code here
mapIsReady = true;
}
});
public boolean mapIsReady() {
return mapIsReady;
}
Then in the activity
#OnClick(R.id.loadListOrMapButton)
public void onClickChangeView() {
// check for null and all that jazz
if (mapsFragment.mapIsReady()) {
// updateDisplay and everything
} else {
// make a toast or something asking them to try later.
}
}
xml
<com.google.android.gms.maps.MapView
android:id="#+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:apiKey="#string/google_app_id"
android:clickable="true">
</com.google.android.gms.maps.MapView>
MainActivity.java
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
LatLng sydney = new LatLng(33.8650, 151.2094);
MapView mapView;
GoogleMap map;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.mapview);
mapView.getMapAsync(this);
MapsInitializer.initialize(this); /* initialize method should be called when we are not sure that map will be loaded before using it. It initialises the map.*/
mapView.onCreate(null);
mapView.onResume();
}
#Override
public void onMapReady(GoogleMap googleMap) {
map = googleMap;
map.addMarker(new MarkerOptions().position(sydney).draggable(true));
}
}