I have an activity which includes an imageview.
When I click on that image,a dialog fragment is shown consisting of html content and a button.
When I click on that button, I want to close this dialog fragment.
I tried to use function dismiss() but it was useless, the dialog fragment does not close, it refreshes actually, and sometimes closes after 3-4 touches on the button!.
Here's my code for the activity:
public class MainActivity extends FragmentActivity implements OnMapReadyCallback,GeneralCallback {
private static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 1;
private Polyline line;
private GoogleMap googleMap;
private Controller controller;
private JSONObject UserDetails;
private JSONArray routePath;
private JSONArray stopPoints;
private List<LatLng> pointsRoutePath;
private List<LatLng> pointsStopPoints;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
controller=new Controller(this);
requireLocationPermissions();
initializeGoogleMap();
configureImage();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_ID_MULTIPLE_PERMISSIONS: {
Map<String, Integer> perms = new HashMap<String, Integer>();
// Initialize the map with both permissions
perms.put(android.Manifest.permission.ACCESS_COARSE_LOCATION, PackageManager.PERMISSION_GRANTED);
perms.put(android.Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
// Fill with actual results from user
if (grantResults.length > 0) {
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
}
}
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
setZoomedLocation(googleMap);
controller.getUserDetails();
this.googleMap=googleMap;
}
//This function is used to require location permissions from the user during run time.
private void requireLocationPermissions(){
RequestPermissions requestPermissions = new RequestPermissions(this, this);
requestPermissions.checkAndRequestPermissions();
}
//This function is used to initialize Google Map Fragment
private void initializeGoogleMap(){
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void VolleyResponse(JSONObject response, String data) {
if (data.equals("getUserDetails")) {
try {
if(response!=null){
Log.i("onResponse","Callback");
UserDetails=response.getJSONObject("InnerData").getJSONObject("user");
routePath=getRoutePath();
stopPoints=getStopPoints();
decodePoly();
drawPath();
putStopMarkers();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
else if(data.equals("AboutUs")){
Log.i("onResponse","Callback");
AboutUs aboutUs = (AboutUs) getSupportFragmentManager().findFragmentByTag("AboutUs");
if(aboutUs!=null && response!=null)
aboutUs.initializeContent(response);
}
}
#Nullable
private JSONArray getRoutePath(){
try {
if(UserDetails!=null)
return UserDetails.getJSONObject("bus").getJSONObject("route").getJSONArray("routePath");
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Nullable
private JSONArray getStopPoints(){
try {
if(UserDetails!=null)
return UserDetails.getJSONObject("bus").getJSONObject("route").getJSONArray("stop_points");
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
private void drawPath() {
if (line != null) {
googleMap.clear();
}
for (int z = 0; z < pointsRoutePath.size() - 1; z++) {
LatLng src = pointsRoutePath.get(z);
LatLng dest = pointsRoutePath.get(z + 1);
line = googleMap.addPolyline(new PolylineOptions()
.add(new LatLng(src.latitude, src.longitude),
new LatLng(dest.latitude, dest.longitude))
.width(60).color(Color.rgb(47,191,220)).geodesic(true));
}
}
private void putStopMarkers(){
for(int i=0;i<pointsStopPoints.size();i++){
LatLng point=new LatLng(pointsStopPoints.get(i).latitude,pointsStopPoints.get(i).longitude);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.stop_marker);
bitmap=Bitmap.createScaledBitmap(bitmap,bitmap.getWidth()/10,bitmap.getHeight()/10,false);
googleMap.addMarker(new MarkerOptions().position(point).icon(BitmapDescriptorFactory.fromBitmap(bitmap)));
}
}
private void decodePoly(){
pointsRoutePath = new ArrayList<>();
pointsStopPoints = new ArrayList<>();
for (int i=0;i<routePath.length();i++){
try {
LatLng point=new LatLng(routePath.getJSONObject(i).getDouble("lat"),routePath.getJSONObject(i).getDouble("lng"));
pointsRoutePath.add(point);
} catch (JSONException e) {
e.printStackTrace();
}
}
for (int i=0;i<stopPoints.length();i++){
try {
LatLng point=new LatLng(stopPoints.getJSONObject(i).getDouble("lat"),stopPoints.getJSONObject(i).getDouble("lng"));
pointsStopPoints.add(point);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
private void setZoomedLocation(GoogleMap googleMap){
LocListener locationListener=new LocListener(this);
//checks if location permission is granted
if(locationListener.canGetLocation()){
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(locationListener.getLatitude(), locationListener.getLongitude()), 14.0f));
}
LatLng point=new LatLng(locationListener.getLatitude(),locationListener.getLongitude());
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.marker_hi);
bitmap=Bitmap.createScaledBitmap(bitmap,bitmap.getWidth()/10,bitmap.getHeight()/10,false);
googleMap.addMarker(new MarkerOptions().position(point).icon(BitmapDescriptorFactory.fromBitmap(bitmap)));
}
private void configureImage(){
ImageView aboutUs=findViewById(R.id.AboutUs);
aboutUs.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
AboutUs aboutUsFragment = new AboutUs();
// Show DialogFragment
aboutUsFragment.show(getSupportFragmentManager(), "AboutUs");
controller.aboutUS();
return true;
}
});
}
}
and here's my code for the dialog fragment:
public class AboutUs extends DialogFragment{
Controller controller;
private View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.about_us, container, false);
controller = new Controller(getActivity());
configureBackButton();
return view;
}
private void configureBackButton(){
Button backButton=view.findViewById(R.id.backButton);
backButton.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("onTouch","onTouch");
getDialog().dismiss();
return true;
}
});
}
public void initializeContent(JSONObject response){
try {
String content=response.getJSONArray("InnerData").getJSONObject(0).getString("content");
WebView webView = view.findViewById(R.id.html);
webView.loadDataWithBaseURL(null, content, "text/html", "utf-8", null);
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onResume() {
super.onResume();
controller.aboutUS();
}
#Override
public void onDismiss(DialogInterface frag) {
dismissAllowingStateLoss();
// DO Something
}
}
Here's about_us.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/RelativeLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="0dp"
android:layout_marginTop="250dp">
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="#+id/html"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
/>
</ScrollView>
<Button
android:id="#+id/backButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="25dp"
android:background="#drawable/button_style"
android:gravity="top|bottom|center"
android:padding="10dp"
android:text="Dismiss"
android:textColor="#ffffff"
android:paddingBottom="20dp"/>
</RelativeLayout>
Replace the onTouchListener in your backButton with an onClickListener.
backButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getDialog().dismiss();
}
});
Click listeners are the recommended approach for buttons. Hopefully, this would make the behaviour of the button and the dialog fragment more predictable and deterministic.
Related
I need to loads some KMZ/KML (I tryed both) in my Google Map MapView instance.
But they load really slow, they are 8 KMZ of around 300KB each and for each one it takes more than 3/4 seconds to get loaded.
How can I solve this?
Surfing in search of a solution I found they suggest to use the V3 version because it fix a polyline creation cycle really time consuming in V2.
This is the library:
implementation 'com.google.maps.android:android-maps-utils-v3:1.3.1'
The problem is that when I use this library the constructors of KmlLayer stop working because inside the class KmlLayer it doesn't found the following package of the GoogleMap class, so because all the constructors require a GoogleMap instance they stop working:
import com.google.android.libraries.maps.GoogleMap;
How can I solve this? Is using the V3 version a solution to my problem? If no how can I solve this?
I found other people having the same problem but when they load KML of 10MB or more and not of just 300KB...
This is the class where there is the MapView instance:
public class MappaNuovoGuastoFragment extends Fragment
implements OnMapReadyCallback,
GetLocationManager.OnLocationUpdateCallback,
GoogleMap.OnMapClickListener,
GoogleMap.OnMapLongClickListener,
BaseRetrofitHelper.INetworkResponseCallback {
private static final String TAG = MappaNuovoGuastoFragment.class.getSimpleName();
// Requests Codes - Permission
private static final int REQ_PERMISSION_LOCATION = 0xB01;
// Requests Codes - Networking
private static final int REQ_CODE_PLACES_AUTOCOMPLETE = 0x1;
private static final int REQ_CODE_GET_PLACE_DETAIL = 0x2;
#BindView(R.id.ll_search)
protected LinearLayout mllSearch;
#BindView(R.id.actv_search_field)
protected AutoCompleteTextView mactvSearchField;
#BindView(R.id.map_view)
protected MapView mMapView;
private GoogleMap mGoogleMap;
private GetLocationManager mGetLocationManager;
private LatLng mMyLocation;
private LatLng mClickedLocation;
private Marker mMarker;
private List<GoogleMapPlace> mPlaces;
public static MappaNuovoGuastoFragment newInstance(){
return new MappaNuovoGuastoFragment();
}
//region [#] Override Lifecycle Methods
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_mappa_nuovo_guasto, container, false);
ButterKnife.bind(this, view);
initOnCreateView(savedInstanceState);
return view;
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQ_PERMISSION_LOCATION) {
if (grantResults.length > 0x0) {
for (int res : grantResults) {
if (res == PackageManager.PERMISSION_GRANTED) {
mMapView.getMapAsync(this);
break;
}
}
}
}
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
mGetLocationManager.startLocationUpdates();
}
#Override
public void onPause() {
mGetLocationManager.stopLocationUpdates();
mMapView.onPause();
super.onPause();
}
#Override
public void onDestroy() {
if(mMapView != null){
mMapView.onDestroy();
}
super.onDestroy();
}
#Override
public void onLowMemory() {
mMapView.onLowMemory();
super.onLowMemory();
}
//endregion
//region [#] Actions Methods
#OnClick(R.id.ib_search)
void onClickSearch(View view){
GoogleMapPlace place = null;
if(mPlaces != null && !mPlaces.isEmpty()){
for(GoogleMapPlace p : mPlaces){
if(p.getDescription().equals(mactvSearchField.getText().toString())){
place = p;
break;
}
}
}
if(place != null){
requestPlaceDetails(place.getPlaceId());
} else {
showSnackbarLocationNotFound();
}
}
#OnClick(R.id.b_make)
void onClickMake(View view){
if(mClickedLocation != null || mMyLocation != null){
startActivityGeneraGuasto();
}
}
#OnClick(R.id.b_map_type)
void onClickMapType(View view){
if(mGoogleMap != null){
switch (mGoogleMap.getMapType()){
case GoogleMap.MAP_TYPE_NONE:
case GoogleMap.MAP_TYPE_HYBRID:
case GoogleMap.MAP_TYPE_SATELLITE:
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
break;
case GoogleMap.MAP_TYPE_NORMAL:
case GoogleMap.MAP_TYPE_TERRAIN:
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
break;
}
}
}
//endregion
//region [#] Override OnMapReadyCallback Methods
#Override
public void onMapReady(#NonNull GoogleMap googleMap) {
mGoogleMap = googleMap;
initGoogleMap();
loadKmz();
}
//endregion
//region [#] Override GetLocationManager.OnLocationUpdateCallback Methods
#Override
public void onLocationUpdated(#Nullable Location location) {
if(mMyLocation == null){
mMyLocation = location != null ? new LatLng(location.getLatitude(), location.getLongitude()) : null;
if(mMyLocation != null){
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mMyLocation, 16.0f));
}
} else {
mMyLocation = location != null ? new LatLng(location.getLatitude(), location.getLongitude()) : null;
}
}
//endregion
//region [#] Override GoogleMap.OnMapClickListener Methods
#Override
public void onMapClick(#NonNull LatLng latLng) {
mClickedLocation = latLng;
initMark();
}
//endregion
//region [#] Override GoogleMap.OnMapLongClickListener Methods
#Override
public void onMapLongClick(#NonNull LatLng latLng) {
if(mClickedLocation != null && PositionUtils.distanceBetween(mClickedLocation.latitude, mClickedLocation.longitude, latLng.latitude, latLng.longitude) <= 100){
mClickedLocation = null;
mMarker.remove();
mMarker = null;
}
}
//endregion
//region [#] Override BaseRetrofitHelper.INetworkResponseCallback Methods
#Override
public void onNetworkResponseSuccess(int requestCode, Object answer) {
switch (requestCode){
case REQ_CODE_PLACES_AUTOCOMPLETE:
if(answer != null){
mPlaces = ((GoogleApiPlaceAutocompleteResponse)answer).getPlaces();
List<String> strings = new ArrayList<>();
for(GoogleMapPlace place : mPlaces){
strings.add(place.getDescription());
}
((ArrayAdapter<String>)mactvSearchField.getAdapter()).clear();
((ArrayAdapter<String>)mactvSearchField.getAdapter()).addAll(strings);
}
break;
case REQ_CODE_GET_PLACE_DETAIL:
if(answer != null){
LatLng latlng = ((GoogleApiPlaceDetailsResponse)answer).getResult().getLatLng();
onMapClick(latlng);
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latlng, 15));
} else {
showSnackbarLocationNotFound();
}
break;
}
}
#Override
public void onNetworkResponseError(int requestCode, Throwable t) {
switch (requestCode){
case REQ_CODE_GET_PLACE_DETAIL:
showSnackbarLocationNotFound();
break;
}
}
//endregion
//region [#] Private Methods
private void initOnCreateView(Bundle savedInstanceState){
mMapView.onCreate(savedInstanceState);
mMapView.onResume();
try {
MapsInitializer.initialize(requireActivity().getApplicationContext());
} catch (Exception e){
EMaxLogger.onException(TAG, e);
e.printStackTrace();
}
mMapView.getMapAsync(this);
mGetLocationManager = GetLocationManager.initInstance(requireActivity()).setCallback(this);
initAutocompleteTextView();
mllSearch.bringToFront();
}
private void initGoogleMap(){
if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(requireActivity(), new String[]{ Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION }, REQ_PERMISSION_LOCATION);
} else {
mGoogleMap.setMyLocationEnabled(true);
}
mGoogleMap.setOnMapClickListener(this);
mGoogleMap.setOnMapLongClickListener(this);
}
private void initMark(){
if(mMarker != null){
mMarker.remove();
}
LatLng pos = new LatLng(mClickedLocation.latitude, mClickedLocation.longitude);
MarkerOptions opt = new MarkerOptions().position(pos).title(getString(R.string.label_nuovo_guasto));
opt.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_mark_work));
mMarker = mGoogleMap.addMarker(opt);
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(pos, 16.0f));
if (mMarker != null) {
mMarker.showInfoWindow();
}
}
private void initAutocompleteTextView(){
ArrayAdapter<String> adapter = new ArrayAdapter<String>(requireContext(), android.R.layout.select_dialog_item, new ArrayList<>());
mactvSearchField.setThreshold(0x4);
mactvSearchField.setAdapter(adapter);
mactvSearchField.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if(s.toString().length() >= 0x4){
requestPlaceAutocomplete(s.toString());
}
}
});
}
private void startActivityGeneraGuasto(){
startActivity(GeneraGuastoActivity.getIntent(requireContext(), mClickedLocation != null ? mClickedLocation.latitude : mMyLocation.latitude, mClickedLocation != null ? mClickedLocation.longitude : mMyLocation.longitude));
}
private void showSnackbarLocationNotFound(){
DesignUtils.showSnackbar(mactvSearchField, getString(R.string.error_location_not_found), Snackbar.LENGTH_SHORT);
}
//region [#] Requests Methods
private void requestPlaceAutocomplete(String input){
String key = getString(R.string.google_maps_key);
String components = String.format("country:%1$s", ((TelephonyManager)getActivity().getSystemService(Context.TELEPHONY_SERVICE)).getNetworkCountryIso());
TicketRetrofitHelper.getInstance().requestAsyncGetPlaceAutocomplete(TicketConstants.URL_GOOGLE_API_PLACE_AUTOCOMPLETE, key, input, components, REQ_CODE_PLACES_AUTOCOMPLETE, this);
}
private void requestPlaceDetails(String idPlace){
String key = getString(R.string.google_maps_key);
TicketRetrofitHelper.getInstance().requestAsyncGetPlaceDetails(TicketConstants.URL_GOOGLE_API_PLACE_DETAILS, key, idPlace, REQ_CODE_GET_PLACE_DETAIL, this);
}
//endregion
private void loadKmz(){
try {
KmlLayer kmz1 = new KmlLayer(mGoogleMap, R.raw.centri_abitati_1, requireContext());
KmlLayer kmz2 = new KmlLayer(mGoogleMap, R.raw.centri_abitati_2, requireContext());
KmlLayer kmz3 = new KmlLayer(mGoogleMap, R.raw.confini_comuni_1, requireContext());
KmlLayer kmz4 = new KmlLayer(mGoogleMap, R.raw.confini_comuni_2, requireContext());
KmlLayer kmz5 = new KmlLayer(mGoogleMap, R.raw.viabilita_1, requireContext());
KmlLayer kmz6 = new KmlLayer(mGoogleMap, R.raw.viabilita_2, requireContext());
KmlLayer kmz7 = new KmlLayer(mGoogleMap, R.raw.viabilita_3, requireContext());
KmlLayer kmz8 = new KmlLayer(mGoogleMap, R.raw.viabilita_4, requireContext());
kmz1.addLayerToMap();
kmz2.addLayerToMap();
kmz3.addLayerToMap();
kmz4.addLayerToMap();
kmz5.addLayerToMap();
kmz6.addLayerToMap();
kmz7.addLayerToMap();
kmz8.addLayerToMap();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//endregion
}
Main Activity
public class MainActivity extends AppCompatActivity implements LocationEngineListener, PermissionsListener{
private MapView mapView;
private MapboxMap map;
private PermissionsManager permissionsManager;
private LocationLayerPlugin locationPlugin;
private LocationEngine locationEngine;
private Location originLocation;
private Marker destinationMarker;
private LatLng originCoord;
private LatLng destinationCoord;
private Point originPosition;
private Point destinationPosition;
private DirectionsRoute currentRoute;
private static final String TAG = "DirectionsActivity";
private NavigationMapRoute navigationMapRoute;
private Button button;
private ArrayList <String> mNames=new ArrayList<>();
private ArrayList <String> mImages=new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Mapbox.getInstance(this,getString(R.string.token));
setContentView(R.layout.activity_main);
mapView=(MapView)findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
button = findViewById(R.id.startnav);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Point origin = originPosition;
Point destination = destinationPosition;
// Pass in your Amazon Polly pool id for speech synthesis using Amazon Polly
// Set to null to use the default Android speech synthesizer
String awsPoolId = null;
boolean simulateRoute = true;
NavigationViewOptions options = NavigationViewOptions.builder()
.origin(origin)
.destination(destination)
.awsPoolId(awsPoolId)
.shouldSimulateRoute(simulateRoute)
.build();
// Call this method with Context from within an Activity
NavigationLauncher.startNavigation(MainActivity.this, options);
}
});
mapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(final MapboxMap mapboxMap) {
map = mapboxMap;
enableLocationPlugin();
originCoord = new LatLng(originLocation.getLatitude(), originLocation.getLongitude());
mapboxMap.addOnMapClickListener(new MapboxMap.OnMapClickListener() {
#Override
public void onMapClick(#NonNull LatLng point) {
button.setEnabled(true);
button.setBackgroundResource(R.drawable.button_press);
if (destinationMarker != null) {
mapboxMap.removeMarker(destinationMarker);
}
destinationCoord = point;
destinationMarker = mapboxMap.addMarker(new MarkerOptions()
.position(destinationCoord)
);
destinationPosition = Point.fromLngLat(destinationCoord.getLongitude(), destinationCoord.getLatitude());
originPosition = Point.fromLngLat(originCoord.getLongitude(), originCoord.getLatitude());
getRoute(originPosition, destinationPosition);
}
});
}
});
getImages();
}
private void getImages() {
Log.d(TAG, "initImageBitmaps: preparing bitmaps");
mImages.add("https://c1.staticflickr.com/5/4636/25316407448_de5fbf183d_o.jpg");
mNames.add("Havasu Falls");
mImages.add("https://i.redd.it/tpsnoz5bzo501.jpg");
mNames.add("Trondheim");
mImages.add("https://i.redd.it/qn7f9oqu7o501.jpg");
mNames.add("Portugal");
mImages.add("https://i.redd.it/j6myfqglup501.jpg");
mNames.add("Rocky Mountain National Park");
mImages.add("https://i.redd.it/0h2gm1ix6p501.jpg");
mNames.add("Mahahual");
mImages.add("https://i.redd.it/k98uzl68eh501.jpg");
mNames.add("Frozen Lake");
mImages.add("https://i.redd.it/glin0nwndo501.jpg");
mNames.add("White Sands Desert");
mImages.add("https://i.redd.it/obx4zydshg601.jpg");
mNames.add("Austrailia");
mImages.add("https://i.imgur.com/ZcLLrkY.jpg");
mNames.add("Washington");
InitRecyclerView();
}
private void InitRecyclerView() {
Log.d(TAG, "InitRecyclerView: init recyclerview");
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);
RecyclerView recyclerView=findViewById(R.id.myrecyclerview);
recyclerView.setLayoutManager(linearLayoutManager);
MainAdapter adapter=new MainAdapter(this,mNames,mImages);
recyclerView.setAdapter(adapter);
}
#SuppressWarnings( {"MissingPermission"})
private void enableLocationPlugin() {
// verifica daca are permission si le cere
if (PermissionsManager.areLocationPermissionsGranted(this)) {
// Create an instance of LOST location engine
initializeLocationEngine();
locationPlugin = new LocationLayerPlugin(mapView, map, locationEngine);
locationPlugin.setLocationLayerEnabled(LocationLayerMode.TRACKING);
} else {
permissionsManager = new PermissionsManager( this);
permissionsManager.requestLocationPermissions(this);
}
}
#SuppressWarnings( {"MissingPermission"})
private void initializeLocationEngine() {
locationEngine = new LostLocationEngine(MainActivity.this);
locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY);
locationEngine.activate();
Location lastLocation = locationEngine.getLastLocation();
if (lastLocation != null) {
originLocation = lastLocation;
setCameraPosition(lastLocation);
} else {
locationEngine.addLocationEngineListener(this);
}
}
private void setCameraPosition(Location location) {
map.animateCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(location.getLatitude(), location.getLongitude()), 13));
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
#Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
}
#Override
public void onPermissionResult(boolean granted) {
if (granted) {
enableLocationPlugin();
} else {
finish();
}
}
#Override
#SuppressWarnings( {"MissingPermission"})
public void onConnected() {
locationEngine.requestLocationUpdates();
}
#Override
public void onLocationChanged(Location location) {
if (location != null) {
originLocation = location;
setCameraPosition(location);
locationEngine.removeLocationEngineListener(this);
}
}
#Override
#SuppressWarnings( {"MissingPermission"})
protected void onStart() {
super.onStart();
if (locationEngine != null) {
locationEngine.requestLocationUpdates();
}
if (locationPlugin != null) {
locationPlugin.onStart();
}
mapView.onStart();
}
#Override
protected void onStop() {
super.onStop();
if (locationEngine != null) {
locationEngine.removeLocationUpdates();
}
if (locationPlugin != null) {
locationPlugin.onStop();
}
mapView.onStop();
}
#Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
if (locationEngine != null) {
locationEngine.deactivate();
}
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
#Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
#Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
private void getRoute(Point origin, Point destination) {
NavigationRoute.builder()
.accessToken(Mapbox.getAccessToken())
.origin(origin)
.destination(destination)
.build()
.getRoute(new Callback<DirectionsResponse>() {
#Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
// You can get the generic HTTP info about the response
Log.d(TAG, "Response code: " + response.code());
if (response.body() == null) {
Log.e(TAG, "No routes found, make sure you set the right user and access token.");
return;
} else if (response.body().routes().size() < 1) {
Log.e(TAG, "No routes found");
return;
}
currentRoute = response.body().routes().get(0);
// Draw the route on the map
if (navigationMapRoute != null) {
navigationMapRoute.removeRoute();
} else {
navigationMapRoute = new NavigationMapRoute(null, mapView, map, R.style.NavigationMapRoute);
}
navigationMapRoute.addRoute(currentRoute);
}
#Override
public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
Log.e(TAG, "Error: " + throwable.getMessage());
}
});
}
}
And the MainAdapter
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {
private static final String TAG="MainAdapter";
private ArrayList <String> mNames=new ArrayList<>();
private ArrayList <String> mImages=new ArrayList<>();
private Context mContext;
public MainAdapter(Context context , ArrayList<String> images, ArrayList<String> names) {
mNames=names;
mImages=images;
mContext=context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d(TAG, "onCreateViewHolder: called ");
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder: called");
Glide.with(mContext)
.asBitmap()
.load(mImages.get(position))
.into(holder.image);
holder.name.setText(mNames.get(position));
holder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: clicked on a image"+mNames.get(position));
Toast.makeText(mContext,mNames.get(position),Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return mImages.size();
}
public class ViewHolder extends RecyclerView.ViewHolder
{
CircleImageView image;
TextView name;
public ViewHolder(View itemView) {
super(itemView);
image=itemView.findViewById(R.id.image_view);
name=itemView.findViewById(R.id.name);
}
}
}
This is activitymain layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.matei.meetup.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/myrecyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" />
<com.mapbox.mapboxsdk.maps.MapView
android:id="#+id/mapView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
mapbox:mapbox_cameraTargetLat="38.9098"
mapbox:mapbox_cameraTargetLng="-77.0295"
mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v10"
mapbox:mapbox_cameraZoom="12" >
</com.mapbox.mapboxsdk.maps.MapView>
<Button
android:id="#+id/startnav"
android:layout_width="316dp"
android:layout_height="41dp"
android:layout_margin="20px"
android:background="#drawable/button_unpressed"
android:padding="5px"
android:text="Start navigation"
android:textColor="#color/mapboxWhite"
mapbox:layout_constraintBottom_toBottomOf="parent"
mapbox:layout_constraintLeft_toLeftOf="parent"
mapbox:layout_constraintRight_toRightOf="parent"
mapbox:layout_constraintTop_toBottomOf="#+id/mapView"
mapbox:layout_constraintVertical_bias="1.0" />
</android.support.constraint.ConstraintLayout>
And here is the other layout file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="1dp">
<android.support.v7.widget.CardView
android:layout_width="100dp"
android:layout_height="100dp"
app:cardCornerRadius="4dp"
app:cardElevation="1dp"
app:cardMaxElevation="2dp"
android:layout_centerInParent="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:scaleType="centerCrop"
android:layout_centerHorizontal="true"
android:id="#+id/image_view"
android:src="#mipmap/ic_launcher"/>
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:text="Chestie"
android:layout_below="#+id/image_view"
android:layout_centerHorizontal="true"
android:gravity="center"
android:layout_marginTop="5dp"
android:textColor="#000"
android:layout_marginBottom="5dp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
The app does not crash on runtime, it only displays the map without the RecyclerView. In my gradle file i inlcuded the dependencies i needed. I tried messing around with the gradle file, nothing seems to work. In my logcat I have the following java.io.FileNotFoundException-No such file or directory.
Problem in library de.hdodenhof.circleimageview.CircleImageView. check this
https://github.com/hdodenhof/CircleImageView/issues/121
If you need to circle imageview you can use glide transformation with imageview
https://bumptech.github.io/glide/doc/transformations.html
Example glide v4:
RequestOptions options = new RequestOptions();
options.CircleCrop();
Glide.with(fragment)
.load(url)
.apply(options)
.into(imageView);
So, basically i was trying to put a button on top of my map fragment but it doesn't seems to work despite the map working completely fine. Even after extensively searching Google, I couldn't find an executable answer.
Here's my map fragment-
public class Tab1 extends SupportMapFragment implements
GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks,
GoogleMap.OnInfoWindowClickListener, OnMapReadyCallback,
ClusterManager.OnClusterClickListener<MyItem>,
ClusterManager.OnClusterInfoWindowClickListener<MyItem>,
ClusterManager.OnClusterItemClickListener<MyItem> {
InputStream inputstream;
BufferedReader reader;
String title;
GoogleMap map;
AutoCompleteTextView actv;
Map<String, String> moviemap;
List<MyItem> items = new ArrayList<MyItem>();
String subtitle;
String floor;
String type;
Double lat;
Double lng;
int len;
int arraylength;
ClusterManager<MyItem> mClusterManager;
List<Map<String, String>> moviedata;
JSONArray jsonArray;
JSONObject jsonObject;
String m;
private GoogleApiClient mGoogleApiClient;
private Location mCurrentLocation;
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mClusterManager = new ClusterManager<MyItem>(getActivity(), getMap());
getMap().setOnCameraChangeListener(mClusterManager);
getMap().setOnMarkerClickListener(mClusterManager);
mClusterManager
.setOnClusterClickListener(new ClusterManager.OnClusterClickListener<MyItem>() {
#Override
public boolean onClusterClick(final Cluster<MyItem> cluster) {
getMap().animateCamera(CameraUpdateFactory.newLatLngZoom(
cluster.getPosition(), (float) Math.floor(getMap()
.getCameraPosition().zoom + 2)), 300,
null);
return true;
}
});
try {
inputstream = getResources().getAssets().open("map.json");
reader = new BufferedReader(new InputStreamReader(inputstream));
m = reader.toString();
StringBuilder total = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
total.append(line);
}
m = total.toString();
} catch (IOException ex) {
Toast.makeText(getActivity(), "fail", Toast.LENGTH_SHORT).show();
}
moviedata = new ArrayList<Map<String, String>>();
try {
jsonObject = new JSONObject(m);
jsonArray = jsonObject.optJSONArray("map");
arraylength = jsonArray.length();
len = arraylength;
for (int i = 0; i < arraylength; i++) {
moviemap = new HashMap<>();
JSONObject jsonChildNode = jsonArray.getJSONObject(i);
title = jsonChildNode.optString("title");
subtitle = jsonChildNode.optString("subtitle");
floor = jsonChildNode.optString("floor");
type = jsonChildNode.optString("type");
lat = jsonChildNode.optDouble("latitude");
lng = jsonChildNode.optDouble("longitude");
moviemap.put("A", title);
moviemap.put("B", subtitle);
moviemap.put("C", floor);
moviemap.put("D", type);
moviemap.put("E", lat.toString());
moviemap.put("F", lng.toString());
moviedata.add(moviemap);
Double lat1 = Double.parseDouble(moviedata.get(i).get("E"));
Double lng1 = Double.parseDouble(moviedata.get(i).get("F"));
items.add(new MyItem(lat1, lng1, moviedata.get(i).get("A"), moviedata.get(i).get("B")));
}
mClusterManager.addItems(items);
mClusterManager.setRenderer(new MyClusterRenderer(getActivity(), getMap(), mClusterManager));
} catch (JSONException e) {
e.printStackTrace();
}
initListeners();
}
private void initListeners() {
getMap().setOnInfoWindowClickListener(this);
}
private void removeListeners() {
if (getMap() != null) {
getMap().setOnInfoWindowClickListener(null);
}
}
#Override
public void onDestroy() {
super.onDestroy();
removeListeners();
}
private void initCamera(Location location) {
CameraPosition position = CameraPosition.builder()
.target(new LatLng(28.75007207311156, 77.11772996932268))
.zoom(18f)
.bearing(0.0f)
.tilt(40f)
.build();
getMap().animateCamera(CameraUpdateFactory.newCameraPosition(position), null);
getMap().setMapType(GoogleMap.MAP_TYPE_NORMAL);
getMap().setTrafficEnabled(true);
getMap().setMyLocationEnabled(true);
getMap().getUiSettings().setZoomControlsEnabled(true);
}
#Override
public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
public void onStop() {
super.onStop();
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
#Override
public void onConnected(Bundle bundle) {
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
initCamera(mCurrentLocation);
}
#Override
public void onConnectionSuspended(int i) {
//handle play services disconnecting if location is being constantly used
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
//Create a default location if the Google API Client fails. Placing location at Googleplex
mCurrentLocation = new Location("");
mCurrentLocation.setLatitude(28.7499);
mCurrentLocation.setLongitude(77.1170);
initCamera(mCurrentLocation);
}
#Override
public void onInfoWindowClick(Marker marker) {
}
#Override
public void onCreateOptionsMenu(
Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_main, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
#Override
public void onMapReady(GoogleMap googleMap) {
map = googleMap;
}
#Override
public boolean onClusterClick(Cluster<MyItem> cluster) {
return false;
}
#Override
public void onClusterInfoWindowClick(Cluster<MyItem> cluster) {
}
#Override
public boolean onClusterItemClick(MyItem myItem) {
return false;
}
}
Here's my xml-
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button"
android:id="#+id/button2"
android:layout_gravity="center" />
</FrameLayout>
use FrameLayout instead of RelativeLayout just like below.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button"
android:id="#+id/button2"
android:layout_gravity="left|top" />
</FrameLayout>
I'm creating a MapFragment in android; maps is showing just fine (although it takes 10 seconds to open), but no marker is shown.
This is the code of the fragment:
public class VehiclesMapFragment extends MapFragment implements OnMapReadyCallback {
GoogleMap _map;
private void setUpMapIfNeeded() {
if (_map == null) {
_map = this.getMap();
//_map = this.getMap();
//if (_map != null) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
ReDrawList(_vehicles);
}
}, 2000);
//}
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
_map = googleMap;
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
ReDrawList(_vehicles);
}
}, 10000);
}
public VehiclesMapFragment() {
}
VehiclesPosition[] _vehicles = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
_vehicles = (VehiclesPosition[])getArguments().getSerializable("VEHICLES");
//setUpMapIfNeeded();
}
public void ReDrawList(VehiclesPosition[] vehicles)
{
if (vehicles != null && vehicles.length > 0 && _map != null) {
LatLngBounds bounds = null;
for (VehiclesPosition vp : vehicles) {
LatLng latlngPos = vp.GetMapLatLng();
if (bounds == null)
bounds = new LatLngBounds(latlngPos, latlngPos);
else
bounds = bounds.including(latlngPos);
MarkerOptions mi = vp.GetMapMarker();
Marker mm = _map.addMarker(mi);
mm.showInfoWindow();
}
try{
_map.animateCamera(CameraUpdateFactory.zoomTo(12));
_map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds,100));
}catch (Exception exx) {
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_vehicles_map, container, false);
setUpMapIfNeeded();
return v;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//setUpMapIfNeeded();
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
#Override
public void onResume() {
super.onResume();
}
private OnFragmentInteractionListener mListener;
public interface OnFragmentInteractionListener {
public void onFragmentInteraction(Uri uri);
}
}
and this is the layout file:
<fragment 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"
android:id="#+id/map"
tools:context=".MapsActivity"
android:name="com.google.android.gms.maps.SupportMapFragment" />
and the fragment is instantiated by an activity, with:
Bundle args = new Bundle();
args.putSerializable("VEHICLES",_VehiclesList);
fragment_units_map = new VehiclesMapFragment();
_fragment_units_map.setArguments(args);
calling _map.animateCamera produce an exception at every call:
java.lang.IllegalStateException: Error using newLatLngBounds(LatLngBounds, int): Map size can't be 0. Most likely, layout has not yet occured for the map view. Either wait until layout has occurred or use newLatLngBounds(LatLngBounds, int, int, int) which allows you to specify the map's dimensions.
I want to geocode address as soon as map center has been changed.
How can I handle map moveend with new Google Maps for Android V2? (I'm talking about the case then user drags map by finger)
Check out new maps api.
#Override
public void onMapReady(GoogleMap map) {
mMap = map;
mMap.setOnCameraIdleListener(this);
mMap.setOnCameraMoveStartedListener(this);
mMap.setOnCameraMoveListener(this);
mMap.setOnCameraMoveCanceledListener(this);
// Show Sydney on the map.
mMap.moveCamera(CameraUpdateFactory
.newLatLngZoom(new LatLng(-33.87365, 151.20689), 10));
}
#Override
public void onCameraMoveStarted(int reason) {
if (reason == OnCameraMoveStartedListener.REASON_GESTURE) {
Toast.makeText(this, "The user gestured on the map.",
Toast.LENGTH_SHORT).show();
} else if (reason == OnCameraMoveStartedListener
.REASON_API_ANIMATION) {
Toast.makeText(this, "The user tapped something on the map.",
Toast.LENGTH_SHORT).show();
} else if (reason == OnCameraMoveStartedListener
.REASON_DEVELOPER_ANIMATION) {
Toast.makeText(this, "The app moved the camera.",
Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCameraMove() {
Toast.makeText(this, "The camera is moving.",
Toast.LENGTH_SHORT).show();
}
#Override
public void onCameraMoveCanceled() {
Toast.makeText(this, "Camera movement canceled.",
Toast.LENGTH_SHORT).show();
}
#Override
public void onCameraIdle() {
Toast.makeText(this, "The camera has stopped moving.",
Toast.LENGTH_SHORT).show();
}
developers.google.com sample
Here is a possible workaround for determining drag start and drag end events:
You have to extend SupportMapFragment or MapFragment. In onCreateView you have to wrap your MapView in a customized FrameLayout (in example below it is the class "TouchableWrapper"), in which you intercepts touch events and recognizes whether the map is tapped or not. If your "onCameraChange" gets called, just check whether the map view is pressed or not (in example below this is the variable "mMapIsTouched").
Example code:
UPDATE 1:
return original created view in getView()
use dispatchTouchEvent() instead of onInterceptTouchEvent()
Customized FrameLayout:
private class TouchableWrapper extends FrameLayout {
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mMapIsTouched = true;
break;
case MotionEvent.ACTION_UP:
mMapIsTouched = false;
break;
}
return super.dispatchTouchEvent(ev);
}
}
In your customized MapFragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
mOriginalContentView = super.onCreateView(inflater, parent,
savedInstanceState);
mTouchView = new TouchableWrapper(getActivity());
mTouchView.addView(mOriginalContentView);
return mTouchView;
}
#Override
public View getView() {
return mOriginalContentView;
}
In your camera change callback method:
private final OnCameraChangeListener mOnCameraChangeListener =
new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition cameraPosition) {
if (!mMapIsTouched) {
refreshClustering(false);
}
}
};
OUTDATED Use the new maps API instead. See answer from punksta.
After using AZ13's solution above, and running into the problem mentioned in the comments, I created the following solution, that solves the issue more reliably. However, since I am using a timer after the onRelease event to determine whether the map is still animating, there is a slight delay in this solution.
The code can be found on Github via this link: https://github.com/MadsFrandsen/MapStateListener
My solution can be used from an activity in the following way:
new MapStateListener(mMap, mMapFragment, this) {
#Override
public void onMapTouched() {
// Map touched
}
#Override
public void onMapReleased() {
// Map released
}
#Override
public void onMapUnsettled() {
// Map unsettled
}
#Override
public void onMapSettled() {
// Map settled
}
};
I would try a onCameraChangeListener. The listener is called every time a movement of the camera is finished. The listener will also give you the new location. In my tests the listener was called pretty often during dragging maybe there is a better solution.
The simplest way is to use setOnCameraIdleListener method to handle your move end state of touch listener on your map fragment.
see the example below:
mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
#Override
public void onCameraMoveStarted(int i) {
mapPin.startAnimation(animZoomOut);
}
});
mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
#Override
public void onCameraIdle() {
mapPin.startAnimation(animZoomIn);
}
});
Starting with play-services-maps 9.4.0 you can simply use GoogleMap.OnCameraMoveStartedListener, GoogleMap.OnCameraMoveListener and GoogleMap.OnCameraIdleListener.
If, for some reason, you want to use the older API which is now deprecated you can use onCameraChangeListener. But you have to be aware of two things:
onCameraChange() might be called many times while you drag the map OR only once (when dragging stopped).
The camera position in the last call of onCameraChange() can be slightly different from the final camera position.
The following code takes both issues into account:
private static final int MESSAGE_ID_SAVE_CAMERA_POSITION = 1;
private static final int MESSAGE_ID_READ_CAMERA_POSITION = 2;
private CameraPosition lastCameraPosition;
private Handler handler;
private GoogleMap googleMap;
public void onMapReady(GoogleMap theGoogleMap) {
googleMap = theGoogleMap;
handler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_ID_SAVE_CAMERA_POSITION) {
lastCameraPosition = googleMap.getCameraPosition();
} else if (msg.what == MESSAGE_ID_READ_CAMERA_POSITION) {
if (lastCameraPosition.equals(googleMap.getCameraPosition())) {
Log.d(LOG, "Camera position stable");
}
}
}
};
googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition cameraPosition) {
handler.removeMessages(MESSAGE_ID_SAVE_CAMERA_POSITION);
handler.removeMessages(MESSAGE_ID_READ_CAMERA_POSITION);
handler.sendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300);
handler.sendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600);
}
});
}
On camera idle is what you should use now
googleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
#Override
public void onCameraIdle() {
//Called when camera movement has ended, there are no pending animations and the user has stopped interacting with the map.
}
});
I have to animate my marker to center as long as the user drag the map. I have implemented it using Stas Shakirov answer
MapDragListenerFragment.class
public class MapDragListenerFragment extends Fragment implements OnMapReadyCallback, GoogleMap.OnMapLoadedCallback {
private Context mContext;
private SupportMapFragment supportMapFragment;
private Marker centerMarker;
private LatLng mapCenterLatLng;
private TextView tvLocationName;
private Button btnFinalizeDestination;
private GoogleMap mGoogleMap;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_map_drag_listener, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mContext = getActivity();
tvLocationName = (TextView) view.findViewById(R.id.tv_location_name);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getActivity().getSupportFragmentManager();//getChildFragmentManager();//
supportMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
if (supportMapFragment == null) {
//// FIXME: 2/13/2017 crashes at casting to TouchableMapFragment
supportMapFragment = SupportMapFragment.newInstance();
fm.beginTransaction().replace(R.id.map_container, supportMapFragment).commit();
}
supportMapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
if (googleMap != null) {
mGoogleMap = googleMap;
centerMarker = mGoogleMap.addMarker(new MarkerOptions().position(mGoogleMap.getCameraPosition().target)
.title("Center of Map")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.end_green)));
mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
#Override
public void onCameraIdle() {
mapCenterLatLng = mGoogleMap.getCameraPosition().target;
animateMarker(centerMarker,mapCenterLatLng,false);
Toast.makeText(mContext, "The camera has stopped moving.",
Toast.LENGTH_SHORT).show();
String address = getCompleteAddressString(mapCenterLatLng.longitude,mapCenterLatLng.longitude);
tvLocationName.setText(address);
}
});
mGoogleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
#Override
public void onCameraMoveStarted(int reason) {
if (reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE) {
///tvLocationName.setText("Lat " + mapCenterLatLng.latitude + " Long :" + mapCenterLatLng.longitude);
Toast.makeText(mContext, "The user gestured on the map.",
Toast.LENGTH_SHORT).show();
} else if (reason == GoogleMap.OnCameraMoveStartedListener
.REASON_API_ANIMATION) {
Toast.makeText(mContext, "The user tapped something on the map.",
Toast.LENGTH_SHORT).show();
} else if (reason == GoogleMap.OnCameraMoveStartedListener
.REASON_DEVELOPER_ANIMATION) {
Toast.makeText(mContext, "The app moved the camera.",
Toast.LENGTH_SHORT).show();
}
}
});
mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
#Override
public void onCameraMove() {
Toast.makeText(mContext, "The camera is moving.",
Toast.LENGTH_SHORT).show();
}
});
mGoogleMap.setOnCameraMoveCanceledListener(new GoogleMap.OnCameraMoveCanceledListener() {
#Override
public void onCameraMoveCanceled() {
Toast.makeText(mContext, "Camera movement canceled.",
Toast.LENGTH_SHORT).show();
}
});
mapCenterLatLng = mGoogleMap.getCameraPosition().target;// it should be done on MapLoaded.
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
return;
}
mGoogleMap.setMyLocationEnabled(true);
mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(15));
mGoogleMap.setOnMapLoadedCallback(this);
mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
#Override
public void onCameraMove() {
}
});
}
}
public void animateMarker(final Marker marker, final LatLng toPosition,
final boolean hideMarker) {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = mGoogleMap.getProjection();
Point startPoint = proj.toScreenLocation(marker.getPosition());
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final long duration = 500;
final Interpolator interpolator = new LinearInterpolator();
handler.post(new Runnable() {
#Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed
/ duration);
double lng = t * toPosition.longitude + (1 - t)
* startLatLng.longitude;
double lat = t * toPosition.latitude + (1 - t)
* startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
} else {
if (hideMarker) {
marker.setVisible(false);
} else {
marker.setVisible(true);
}
}
}
});
}
}
where fragment_map_drag_listener.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<fragment
android:id="#+id/map_container"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="#+id/iv_center_overlay"
android:layout_width="25dp"
android:layout_height="25dp"
android:visibility="gone"
android:layout_centerInParent="true"
android:src="#drawable/start_blue" />
</RelativeLayout>
<TextView
android:id="#+id/tv_location_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:text="Location Name" />
</LinearLayout>
where
MapDragListenerActivity
public class MapDragListenerActivity extends AppCompatActivity {
private Context mContext;
private static final String TAG = MapDragListenerFragment.class.getSimpleName();
private MapDragListenerFragment mapDragListenerFragment;
private Button selectPlaceBtn;
public static final int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1219;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_drag_listener);
mContext = MapDragListenerActivity.this;
mapDragListenerFragment = new MapDragListenerFragment();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_container,//where frame_container is a FrameLayout
mapDragListenerFragment,
MapyFragment.class.getSimpleName()).commit();
selectPlaceBtn = (Button) findViewById(R.id.btn_select_place);
selectPlaceBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
Intent intent = new PlaceAutocomplete.IntentBuilder(
PlaceAutocomplete.MODE_FULLSCREEN).build(MapDragListenerActivity.this);
startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE);
} catch (GooglePlayServicesRepairableException e) {
e.printStackTrace();
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == PLACE_AUTOCOMPLETE_REQUEST_CODE){
if (resultCode == RESULT_OK) {
Place place = PlaceAutocomplete.getPlace(mContext, data);
if(mapDragListenerFragment != null && mapDragListenerFragment.isVisible())
mapDragListenerFragment.updateMarkerAtPosition(
place.getLatLng() ,place.getName().toString());
Log.i(TAG, "Place:" + place.toString());
} else if (resultCode == PlaceAutocomplete.RESULT_ERROR) {
Status status = PlaceAutocomplete.getStatus(mContext, data);
Log.i(TAG, status.getStatusMessage());
} else if (requestCode == RESULT_CANCELED) {
}
}
}
}
activity_map_drag_listener.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="#+id/btn_select_place"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Select Place" />
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
#Override
public boolean onTouchEvent(MotionEvent event, MapView mapView){
if(event.getAction() == MotionEvent.ACTION_MOVE)
return true;
return false;
}
I think the event onclick in the map is: map.setOnMapClick...
But event drag is: map.onCameraChangeListener because I call a log.e in both of that functions and it shown like onClick view and onDrag view . So just using them for you.
Enhanced solution with an Handler inner Class in Xamarin Android, based on Tobus answer:
public void OnMapReady(GoogleMap googleMap)
{
_googleMap = googleMap;
if (_googleMap != null)
{
_cameraPositionHandler = new CameraPositionlHandler(_googleMap);
_googleMap.CameraChange += OnCameraChanged;
}
}
void OnCameraChanged (object sender, GoogleMap.CameraChangeEventArgs e)
{
_cameraPositionHandler.RemoveMessages(MESSAGE_ID_SAVE_CAMERA_POSITION);
_cameraPositionHandler.RemoveMessages(MESSAGE_ID_READ_CAMERA_POSITION);
_cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300);
_cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600);
}
With the following inner Class:
private class CameraPositionlHandler : Handler
{
private CameraPosition _lastCameraPosition;
private GoogleMap _googleMap;
public CameraPositionlHandler (GoogleMap googleMap)
{
_googleMap = googleMap;
}
public override void HandleMessage(Message msg)
{
if (_googleMap != null)
{
if (msg.What == MESSAGE_ID_SAVE_CAMERA_POSITION) {
_lastCameraPosition = _googleMap.CameraPosition;
} else if (msg.What == MESSAGE_ID_READ_CAMERA_POSITION) {
if (_lastCameraPosition.Equals(_googleMap.CameraPosition)) {
Console.WriteLine("Camera position stable");
//do what you want
}
}
}
}
}