I am trying to allow a User to remove a point (or more specifically, an OverlayItem) from a map. I followed the developer tutorial to get started and implemented the CustomMapView in this tutorial to capture a long press on the map.
So now I have a program which allows a User to place points on the map. My next goal is to let the User remove points. Here is my code for when a User clicks an existing point on the map.
public class OurItemizedOverlay extends ItemizedOverlay {
//Create new list of points
private ArrayList<OverlayItem> mapOverlays = new ArrayList<OverlayItem>();
private Context mapContext;
#Override
protected boolean onTap(final int index) {
Button edit, remove;
//Get index of item tapped
OverlayItem item = mapOverlays.get(index);
//Create Dialog to show point info, allow for edit or removal.
LinearLayout layout = new LinearLayout(mapContext);
layout.setOrientation(LinearLayout.VERTICAL);
LayoutInflater inflater = LayoutInflater.from(mapContext);
AlertDialog.Builder builder = new AlertDialog.Builder(mapContext);
builder.setTitle(item.getTitle());
builder.setMessage(item.getSnippet());
View view = inflater.inflate(R.layout.view_or_edit_location_dialog, null);
builder.setView(view);
builder.show();
//BUTTONS
edit = (Button)view.findViewById(R.id.edit);
remove = (Button)view.findViewById(R.id.delete);
//Edit Button Listener
edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
//Remove Button Listener
remove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
removeOverlay(index); <--------
Log.d("View location info", "user clicked delete.");
return;
}
});
return true;
}
Here is my code for removeOverlay.
protected void removeOverlay(int index) {
mapOverlays.remove(index);
com.example.mapproject.MainActivity.mapView.invalidate();
}
After I click on an existing point a dialog is presented offering to remove the point. When I have selected to remove the point, the point still remains on the screen. If I place a new point, the 'deleted' one is removed. However, if I click the 'deleted' point or another existing point, the program crashes with this error.
If you have a clue of what to do, I'd appreciate to hear from you !!
Edit
Following a tip from Vishwa Patel, I remove a point from the map straight away using postInvalidate(). However, I still get indexoutofbounds exceptions when I click where the icon was..
You probably need to call invalidate() on your MapView, forcing it to re-draw itself. As the commenters mentioned, you may also need to re-call populate(). Your app is probably crashing because it's trying to call onTap() for an OverlayItem that doesn't exist. You may also want to try any method that could "refresh" the MapView and/or Overlay, because that is what you need to do to make the OverlayItem disappear.
Try using
com.example.mapproject.MainActivity.mapView.postInvalidate();
since you are making an invalidate call from a non-UI thread, as specified in the documentation for postInvalidate();
I believe I found the solution here. It seems to work so far, the answer was to put the following line into my removeOverlay method,
setLastFocusedIndex(-1);
The code to remove an OverylayItem from my custom Overlay is,
protected void removeOverlay(OverlayItem overlayItem) {
mapOverlays.remove(overlayItem);
MainActivity.mapOverlays.remove(this);
setLastFocusedIndex(-1);
populate();
}
Any thoughts/suggestions are welcome!
Related
I am trying to toggle a heatmap on and off using Android.
I have two lists say:
List<LatLng> a = new ArrayList<>
List<LatLng> b = new ArrayList<>
a.add(new LatLng(53.457131,-1.054688);
a.add(new LatLng(53.036407,-4.570313);
a.add(new LatLng(52.182504, -1.054688);
b.add(new LatLng(45.238325,2.460938);
I combine these two lists:
finalList.addAll(a);
finalList.addAll(b);
I want to toggle these lists in the TileOverlay.
aButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (overlay.isVisible()) {
finalList.removeAll(a);
} else {
finalList.addAll(a);
}
providor.setData(a);
overlay.clearTileCache();
}
and I do the same to the second button.
But once you remove both lists (so finalList is empty) I get the following error:
java.lang.IllegalArgumentException: No input points
I would like to know if there is a easy way to implement this.
I have tried to implement this meathod:
On button click check if finalList.isEmpty() and remove the overlay if it is.
But then that brings its own problems as then I would have to create new overlay.
I also tried to set the overlay to visible but then that messes up the buttonClick Listener as it checks for overlay.isVisible()
Thanks
Here is the problem:
I want to show the user the best route to reach a marker after the user presses a button inside the infoWindow. The problem is, I can't get the marker's Location data due to some problem with Latlng and Position classes. (I am using the Mapbox example to get the route, so I need two Position values)
So basically, I need to update the variable Destination with the marker's position by clicking a button inside the custom infowindow. Yet I have no idea how can I do that even though going through a lot on searching Google and Stack Overflow. Can someone help me? (Cammack!) Thanks a bunch for the help!
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
// Origem: Rodoviaria
final Position origin = Position.fromCoordinates(-47.882645, -15.794082);
// Destino: Reitoria
final Position destination = Position.fromCoordinates(-47.866611, -15.762604);
//...
mapboxMap.setInfoWindowAdapter(new MapboxMap.InfoWindowAdapter() {
#Nullable
#Override
public View getInfoWindow(#NonNull Marker marker) {
//...
final Marker marcador = marker;
botaoIr = (Button)v.findViewById(R.id.botaoIr);
botaoIr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//I have been trying the method below, but I am having trouble with LatLng and Position classes!
//LatLng ponto = marcador.getPosition();
//destination = new Position(ponto.getLongitude(),ponto.getLatitude());
try {
getRoute(origin, destination);
} catch (ServicesException servicesException) {
servicesException.printStackTrace();
}
}
});
}
});
//...
}
To create a position call fromCoordinates().
destination = Position.fromCoordinates(ponto.getLongitude(),ponto.getLatitude());
If you want to remove all annotations on your map, you can call "removeAnnotations()" on your MapBoxMap-Instance:
mapboxMap.removeAnnotations();
..or you can call "remove()" on any annotation from MapBox itself (Polygon, Polyline or Marker)
Polygon pol = new Polygon();
pol.remove();
If it's still existing and you just want to change & update an annotation, call "updatePolygon()", "updateMarker" or "updatePolyline() like this:
mapboxMap.updatePolygon(myPolgonInstance);
mapboxMap.updateMarker(myMarkerInstance);
...
when i searched for it i found these links as solutions:
http://android-codes-examples.blogspot.in/2011/04/google-map-example-in-android-with-info.html
and
https://github.com/jgilfelt/android-mapviewballoons
but i found both are complicated.
I am wondering if there is any simple way to do this. Like inflating a layout and showing it as a pop up just on the marker clicked.
Right now i am using just a Toast to show info when user taps on the marker. But the main problem is I want this toast(or other layout) to appear just above the marker which is clicked, not at the default toast position.
Thank You
Try this, modify according to your requirement:
#SuppressWarnings({ "deprecation" })
#Override
protected boolean onTap(int index)
{
CustomView customView=new CustomView(MyMap.this);
absMap.removeAllViews();
absMap.addView(customView);
customView.setBackgroundResource(R.drawable.maplocation1);
customView.setVisibility(View.INVISIBLE);
customView.removeAllViews();
absMap.invalidate();
customView.bringToFront();
customView.setVisibility(View.VISIBLE);
TextView tv2=new TextView(MyMap.this);
// tv2.setText(overlayItemList.get(index).getTitle());
tv2.setWidth(170);
tv2.setSingleLine(true);
tv2.setEllipsize(TruncateAt.END);
tv2.setSingleLine(true);
tv2.setSingleLine();
tv2.setTextColor(Color.WHITE);
tv2.setTextSize(14);
tv2.setTypeface(Typeface.DEFAULT_BOLD);
TextView tv1=new TextView(MyMap.this);
tv1.setSingleLine();
tv1.setWidth(170);
tv1.setSingleLine(true);
tv1.setEllipsize(TruncateAt.END);
tv1.setSingleLine(true);
tv2.setText(overlayItemList.get(index).getSnippet());
tv1.setTextColor(Color.WHITE);
tv1.setTextSize(12);
tv1.setTypeface(Typeface.DEFAULT_BOLD);
customView.setTag(overlayItemList.get(index).getTitle());
customView.addView(tv2, new AbsoluteLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT,10,5));
customView.addView(tv1, new AbsoluteLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT,10,25));
customView.setLayoutParams(new MapView.LayoutParams( 250, 100, overlayItemList.get(index).getPoint(),-125,-137, MapView.LayoutParams.MODE_MAP|MapView.LayoutParams.TOP_LEFT));
customView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
}
});
}
I have an application that uses the mapview-overlay-manager code to draw map markers on a MapView using the LazyLoadManager from a web api. As I drag the map, the markers load/unload as expected.
On the tap of a marker I inflate a balloon.xml file and use it to show a balloon above the marker. This is where the problem is. It works, but then suddenly (which I cannot repeat on a consistently) the balloon overlay will stop showing up on the screen.
Its odd though, because the marker still shows that its been tapped, but then the balloon stops showing up. I've checked that the balloon is not null (which it is not), and that the itemInfo is not null. Its just not getting added to the MapView after the call to .addView(...), yet all the params are valid.
Side note: Anytime this happens, all of the overlays turn real dark and the overlay shadows go from semi-transparent to black. I have no idea what is causing that, but it happens at the same time, which makes me believe its a drawing problem.
Code for the above problem is below. Any tips/ideas/etc would be appreciated.
#Override
public boolean onSingleTap(MotionEvent e, ManagedOverlay overlay, GeoPoint point, ManagedOverlayItem item) {
if(mBalloon != null)
{
mMapView.removeView(mBalloon);
mBalloon = null;
}
if(item != null) {
//Toast.makeText(getApplicationContext(), item.getTitle(), Toast.LENGTH_SHORT).show();
MapView.LayoutParams balloonLayoutParams = new MapView.LayoutParams(350, MapView.LayoutParams.WRAP_CONTENT, item.getItemInfo().getMarkerPoint(mMapView.getProjection()), MapView.LayoutParams.BOTTOM_CENTER);
if(mBalloon == null) {
if(mLayoutInflater == null) {
mLayoutInflater = getLayoutInflater();
}
ViewGroup parent = (ViewGroup)mMapView.getParent();
mBalloon = (BalloonLayout) mLayoutInflater.inflate(R.layout.balloon_layout, parent, false);
}
TextView title = (TextView)mBalloon.findViewById(R.id.title);
title.setText(item.getItemInfo().getTitle());
TextView subTitle = (TextView)mBalloon.findViewById(R.id.subTitle);
subTitle.setText(item.getItemInfo().getBalloonSubTitle());
if(DEBUG) Log.d(TAG, "Setting on click listener.");
((ImageButton)mBalloon.findViewById(R.id.go_button)).setOnClickListener(new ViewItemInfoListener(item.getItemInfo()));
mMapView.addView(mBalloon, balloonLayoutParams);
}
return false;
}
});
// Fires off the background event to get the
overlayManager.populate();
}
Have you considered during an OnDrag: removing all the markers and save in a temporary list, start a timer (prob 200-500 ms), and then after the timer has expired repopulate the markers. If another OnDrag occurs before the timer expires, then restart the timer.
Ok, I found the problem. There is a parent method calling this method. Unfortunately this method was being called twice. Once on the onFocusChanged() and once in onCreate(). Removing one of them cured the issue. The icons and balloons were double drawing themselves because of this.
I have a DialogPreference and I want to avoid the user from closing it when pressing "OK", "Cancel", etc.
How should I do that?
EDIT:
I tried to reach the OK button to disable when the dialog is created. But I couldn't make it :(
The solution is quite easy. Overwrite showDialog and set your own click listener to the buttons you want to intercept.
#Override
protected void showDialog(Bundle bundle) {
super.showDialog(bundle);
Button pos = ((AlertDialog) getDialog()).getButton(DialogInterface.BUTTON_POSITIVE);
pos.setOnClickListener(...);
}
In your click listener you can do the validation you want.
A tweak could be to create a custom dialog where you define your own buttons (OK and Close).
public class YourClass implements OnClickListener {
private Button DialogButton;
private Dialog dialog;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.MainLayout);
/* Your code... */
DialogButton = (Button) findViewById(R.id.DialogButtonId);
DialogButton.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.DialogButtonId:
LayoutInflater inflater = LayoutInflater.from(YourClass.this);
final View inflay = inflater.inflate(R.layout.DialogLayout, (ViewGroup) findViewById(R.id.RootIdOfDialogLayout));
TextView YourTextView = (TextView) inflay.findViewById(R.id.TextViewId);
Button cancel = (Button) inflay.findViewById(R.id.CancelButtonId);
cancel.setOnClickListener(YourClass.this);
Button ok = (Button) inflay.findViewById(R.id.OkButtonId);
ok.setOnClickListener(YourClass.this);
dialog = new Dialog(YourClass.this);
dialog.setContentView(inflay);
dialog.setTitle(getString(R.string.TitleStringId));
dialog.show();
break;
case R.id.CancelButtonId:
/* Checking if the user selected an option if true call dialog.dismiss() */
break;
case R.id.OkButtonId:
/* Here handle your preferences (e.g. putString(String key, String value)) */
/* Checking if the user selected an option if true call dialog.dismiss() */
break;
}
}
}
Check out http://developer.android.com/reference/android/content/SharedPreferences.Editor.html in order to handle your preference in onClick. I didn't test this code just wrote it to show you how you could solve it!
The dialog stays open until you call dialog.dismiss();. In that case you'll have to create your drop-down-menu, polls or what ever you want to display in your layout file. After pressing ok or cancel you should check if the user made a choice, and parse that choice into your preferences. (check link above)
Rgds
Layne
You could try opening it again.
Why would you want to prevent users to close the dialog? Users should be able to have 'full' control of their device.
You can see the source code of DialogPreferences here:
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/preference/DialogPreference.java
And then, copy most of it to your code, modifying the code as needed.
How about overriding the onDismiss() method and implementing a canExit() method with the validations you want to occcur? E.g. :
public class MyDialogPref extends DialogPreference {
#override public void onDismiss(DialogInterface dialog) {
if (canExit()) {
super.onDismiss(dialog);
}
}
...
}
A good UI should have a default selection/option already selected (the previously user-entered options or a program default).
Presenting a dialog asking for a change in options without any indication of what you already have is bad UI design.
This way if the user clicks Cancel, nothing changes and they saw what the option selected was. If they make no change and click OK then nothing really changes either.
Software is supposed to make doing specific tasks easier, not force the user to process the apps logic themselves.