Line appears in OverlayItem on Google Maps - java

I'm using an ItemizedOverlay on a Google Maps in an Android application. My extension of ItemizedOverlay is shown below.
The strange thing is I see a small line from about the 8 o'clock position to the 2 o'clock position in every occurrence of the overlay. The overlay is a png that is in my application resources (which obviously doesn't have the strange line). I've attached an example of the raw png overlay (R.drawable.green) here:
And here is what I see in the android app:
(You kind of have to look closely to see the gray line I'm talking about. It is under the green dots and under the little airplane icon.)
The overlay is added as follows:
ReportOverlay itemizedoverlay = new ReportOverlay(getResources().getDrawable(R.drawable.green),mContext);
GeoPoint point = new GeoPoint(pr.getLat(),pr.getLng());
OverlayItem overlayitem = new OverlayItem(point, pr.getReport(),pr.getReport());
itemizedoverlay.addOverlay(overlayitem);
Any idea where this mystery line in the overlay is coming from?!
public class ReportOverlay extends ItemizedOverlay<OverlayItem> {
protected ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
Context mContext;
public ReportOverlay(Drawable defaultMarker) {
super(boundCenter(defaultMarker));
}
public ReportOverlay(Drawable defaultMarker, Context context) {
super(boundCenter(defaultMarker));
mContext = context;
}
public void addOverlay(OverlayItem overlay) {
mOverlays.add(overlay);
populate();
}
#Override
protected OverlayItem createItem(int i) {
return mOverlays.get(i);
}
#Override
protected boolean onTap(int index) {
OverlayItem item = mOverlays.get(index);
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
dialog.show();
return true;
}
#Override
public int size() {
return mOverlays.size();
}
}

As MH suggested, it was indeed the shadow that I was seeing. Turning it off fixed the issue.

Related

Add marker to OSMdroid 5.5 map

I want to add markers to my OSMdroid map. I am using OSMdroid version 5.5. The official tutorial suggests the following code:
//your items
ArrayList<OverlayItem> items = new ArrayList<OverlayItem>();
items.add(new OverlayItem("Title", "Description", new GeoPoint(0.0d,0.0d))); // Lat/Lon decimal degrees
//the overlay
ItemizedOverlayWithFocus<OverlayItem> mOverlay = new ItemizedOverlayWithFocus<OverlayItem>(items,
new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
#Override
public boolean onItemSingleTapUp(final int index, final OverlayItem item) {
//do something
return true;
}
#Override
public boolean onItemLongPress(final int index, final OverlayItem item) {
return false;
}
}, mResourceProxy); // <----- where to get this object from?
mOverlay.setFocusItemsOnTap(true);
mMapView.getOverlays().add(mOverlay);
However, I don't know where to get the mResourceProxy object from. All websites I found about this topic (including OSMdroid's GitHub page) are making use of the DefaultResourceProxyImpl class, which is deprecated since version 5.2.
Does anyone know how to add marker versions >= 5.2?
Okay, so I found out how to use it. The ItemizedOverlayWithFocus doesn't require a ResourceProxy at all. So you can use one of the following constructors:
public ItemizedOverlayWithFocus(Context pContext, List<Item> aList, OnItemGestureListener<Item> aOnItemTapListener) { ... }
public ItemizedOverlayWithFocus(List<Item> aList, OnItemGestureListener<Item> aOnItemTapListener, Context pContext) { ... }
public ItemizedOverlayWithFocus(List<Item> aList, Drawable pMarker, Drawable pMarkerFocused, int pFocusedBackgroundColor, OnItemGestureListener<Item> aOnItemTapListener, Context pContext) { ... }
This is how I adjusted the code from my question to make it work:
//your items
ArrayList<OverlayItem> items = new ArrayList<OverlayItem>();
items.add(new OverlayItem("Title", "Description", new GeoPoint(0.0d,0.0d))); // Lat/Lon decimal degrees
//the overlay
ItemizedOverlayWithFocus<OverlayItem> mOverlay = new ItemizedOverlayWithFocus<OverlayItem>(
this, items, // <--------- added Context this as first parameter
new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
#Override
public boolean onItemSingleTapUp(final int index, final OverlayItem item) {
//do something
return true;
}
#Override
public boolean onItemLongPress(final int index, final OverlayItem item) {
return false;
}
}); // <----- removed the mResourceProxy parameter
mOverlay.setFocusItemsOnTap(true);
mMapView.getOverlays().add(mOverlay);

OSMDROID - longPressHelper only fires the first time when it is used to add a marker

I'm using osmdroid and have implemented a MapEventsReceiver, MapEventsOverlay and a LongPressHelper in order to add a new marker when the user holds down on the map. This works the first time and the first time only.
If I remove the addMarker(p); from my longPressHelper then it will fire every single time.
Has anyone got any idea why this is happening like this?
code:
mapviewInit - called in onCreate
private void mapviewInit() {
mapview = (MapView) findViewById(R.id.mapview);
mapview.setTileSource(TileSourceFactory.MAPNIK);
mapview.setBuiltInZoomControls(true);
mapview.setMultiTouchControls(true);
IMapController mapController = mapview.getController();
mapController.setZoom(16);
GeoPoint startPoint = new GeoPoint(48.8583, 2.2944);
mapController.setCenter(startPoint);
MapEventsReceiver meReceiver = new MapEventsReceiver() {
#Override
public boolean singleTapConfirmedHelper(GeoPoint p) {
return false;
}
#Override
public boolean longPressHelper(GeoPoint p) {
Toast toast = Toast.makeText(getApplicationContext(), "DEBUGDEBUGDEBUG", Toast.LENGTH_LONG);
toast.show();
addMarker(p);
return true;
}
};
addMarker - called by LongPressHelper
public void addMarker(GeoPoint geoPoint) {
Drawable dr = getResources().getDrawable(R.drawable.icn_crosshair_red);
Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
Drawable d = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, 100, 100, true));
mapview.getOverlays().clear();
mapview.invalidate();
selectedPosMarker = new Marker(mapview);
selectedPosMarker.setPosition(geoPoint);
selectedPosMarker.setInfoWindow(null);
selectedPosMarker.setIcon(d);
selectedPosMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mapview.getOverlays().add(selectedPosMarker);
mapview.invalidate();
}
I assume you add a MapEventsOverlay somewhere, in a part of your code you didn't provided.
The issue is that you remove it in addMarker! :
mapview.getOverlays().clear();
So of course it is not present to react to long press on the second time...
Don't call mapview.invalidate() twice in the same method, it's useless and time-consuming.

Osmdroid Bonuspack - MyLocationNewOverlay

I currently have a couple of features that are causing a few problems that where originally working but after changing some things around are now producing errors. Using Android Studio which allowed me to look at previous versions of the code but to no avail.
Anyway I have a MyLocationNewOverlay declared globally like so:
MyLocationNewOverlay location_overlay;
Which gets initiated when the user navigates to the activity with the map:
map = (MapView) findViewByID(R.id.map);
map.setVisibility(MapView.VISIBLE);
<..some working code that sets the tile source and the center..>
location_overlay = new MyLocationNewOverlay(getApplicationContext(), map);
location_overlay.enableMyLocation();
location_overlay.setDrawAccuracyEnabled(true);
map.getOverlays().add(location_overlay);
map.invalidate();
When it was working this code displayed a little human marker with the accuracy circle around it but now it doesn't even though it doesn't produce any errors. Iv'e tried the now decrepit MyLocationOverlay which didn't work either.
The second issue lies within an 'onClick' method on a button that supposed to focus the map on the users current location, this also used to work.
public void onBtnFocusOnMe(View view){
GeoPoint gp = new GeoPoint(location_overlay.getMyLocation());
if(gp != null){
mapController.animateTo(gp);
mapController.zoomTo(16);
}
}
Which produces a null pointer error on GeoPoint gp = new GeoPoint(location_overlay.getMyLocation());
How I normally overlay some items is like this, it is not directly your solution but you can maybe extract something useful from here:
public void showStartGoalMarkers(GeoPoint start, GeoPoint goal) {
List<OverlayItem> mStartGoalItems = new ArrayList<>();
OverlayItem startItem = new OverlayItem("", "", start);
Drawable newMarker = mMapView.getContext().getResources().getDrawable(R.drawable.ic_start);
startItem.setMarker(newMarker);
mStartGoalItems.add(startItem);
OverlayItem goalItem = new OverlayItem("", "", goal);
Drawable newMarker2 = mMapView.getContext().getResources().getDrawable(R.drawable.ic_end);
goalItem.setMarker(newMarker2);
mStartGoalItems.add(goalItem);
mMapView.getOverlays().add(new ItemizedIconOverlay<OverlayItem>(mStartGoalItems, new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
#Override
public boolean onItemSingleTapUp(int index, OverlayItem item) {
return false;
}
#Override
public boolean onItemLongPress(int index, OverlayItem item) {
return false;
}
}, mMapView.getResourceProxy()));
}
and in the end you invalidate the map view. Hope it helps.
EDIT: the code for marking the current location and which also updates the current position when a new location is passed:
private void markMyLocation(Location location) {
mOverlayItems.add(0, new OverlayItem("", "", new GeoPoint(location)));
if (mMyLocationOverlay == null) {
mMyLocationOverlay = new MyLocationOverlay(mOverlayItems, new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
#Override
public boolean onItemSingleTapUp(int index, OverlayItem item) {
IMapController mapController = mMapView.getController();
mapController.setCenter(item.getPoint());
mapController.setZoom(mMapView.getMaxZoomLevel());
return true;
}
#Override
public boolean onItemLongPress(int index, OverlayItem item) {
return false;
}
}, mMapView.getResourceProxy());
mMapView.getOverlays().add(mMyLocationOverlay);
mMapView.getController().setZoom(16);
} else {
IMapController mapController = mMapView.getController();
mapController.setCenter(mOverlayItems.get(0).getPoint());
mMapView.invalidate();
}
}
The MyLocationOverlay class:
public class MyLocationOverlay extends ItemizedIconOverlay<OverlayItem> {
List<OverlayItem> mMyLocation;
int mResourceId;
public MyLocationOverlay(List<OverlayItem> pList,
OnItemGestureListener<OverlayItem> pOnItemGestureListener,
ResourceProxy pResourceProxy) {
super(pList, pOnItemGestureListener, pResourceProxy);
this.mMyLocation = pList;
this.mResourceId = R.drawable.my_location;
}
#Override
public void draw(Canvas canvas, MapView mapview, boolean arg2) {
super.draw(canvas, mapview, true);
if (!mMyLocation.isEmpty()) {
IGeoPoint geoPointLocation = mMyLocation.get(0).getPoint();
Point out = new Point();
mapview.getProjection().toPixels(geoPointLocation, out);
Bitmap bm = BitmapFactory.decodeResource(mapview.getResources(),
mResourceId);
canvas.drawBitmap(bm,
out.x - bm.getWidth() / 2, //shift the bitmap center
out.y - bm.getHeight() / 2, //shift the bitmap center
null);
}
}
#Override
public boolean onSingleTapUp(MotionEvent event, MapView mapView) {
// TODO Auto-generated method stub
//return super.onSingleTapUp(event, mapView);
return true;
}
Basically what I do is I overwrite the single item in the ArrayList mOverlayItems when the method is called and invalidate the map.

Marker click event in android map using osm

i am using following code for creating marker(bitmap),how to add click event for marker. i use graphhopper android for OSM map
startMarker = createMarker(startPoint, R.drawable.marker_departure); layers.add(startMarker);
add use createMarker method
public Marker createMarker(LatLong p, int resource) {
Drawable drawable = activity.getResources().getDrawable(resource);
Bitmap bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
return new Marker(p, bitmap, 0, -bitmap.getHeight() / 2);
}
and how to add text near to marker
thanks in advance
Try with this, may be this will help full.
layers.setOnMarkerClickListener(new OnMarkerClickListener()
{
#Override
public boolean onMarkerClick(Marker arg0) {
//Your stuff
});
i use following code its works for me
MyMarker frommarker = newMyMarker(activity,newLatLong(fl.latitude,fl.longitude), AndroidGraphicFactory.convertToBitmap(activity.getResources().getDrawable(R.drawable.marker_departure)), 0, 0);
mapView.getLayerManager().getLayers().add(frommarker);
and mymarker class
public class MyMarker extends Marker {
private Context ctx;
public MyMarker(Context ctx, LatLong latLong, Bitmap bitmap, int horizontalOffset,
int verticalOffset) {
super(latLong, bitmap, horizontalOffset, verticalOffset);
this.ctx = ctx;
}
#Override
public boolean onTap(LatLong tapLatLong, Point layerXY, Point tapXY) {
if (this.contains(layerXY, tapXY)) {
}
}

StateListDrawable to switch colorfilters

I want to create custom buttons to use in a TabHost. I haven been trying to just use the same image resource (png), but have the colorfilter change depending on the state. So I made this bit to serve as the layout for the custom button:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<ImageView android:id="#+id/tab_icon"
android:layout_centerInParent="true" android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView android:id="#+id/tab_text" android:layout_below="#id/tab_icon"
android:layout_centerHorizontal="true" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
In my activity, I add the tabs like this:
tabHost.addTab(tabHost.newTabSpec(TAB_NAME_NEWS).setIndicator(buildTab(R.drawable.tab_icon_news, R.string.news))
.setContent(newsIntent));
And this is the 'buildTab' method:
private final static int[] SELECTED = new int[] { android.R.attr.state_selected };
private final static int[] IDLE = new int[] { -android.R.attr.state_selected };
private View buildTab(int icon, int label) {
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.tab_button, null);
StateListDrawable drawable = new StateListDrawable();
Drawable selected = getResources().getDrawable(icon);
selected.mutate();
selected.setBounds(0, 0, selected.getIntrinsicWidth(), selected.getIntrinsicHeight());
selected.setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0x0000FF00));
drawable.addState(SELECTED, selected);
Drawable idle = getResources().getDrawable(icon);
idle.mutate();
idle.setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0x000000FF));
drawable.addState(IDLE, idle);
((ImageView) view.findViewById(R.id.tab_icon)).setImageDrawable(drawable);
((TextView) view.findViewById(R.id.tab_text)).setText(getString(label));
return view;
}
In the selected state, the image should be completely green (0x0000FF00), and in the non-selected state, it should be blue (0x000000FF).
The problem is that the colorfilters appear to be be completely ignored. I can not see the colors change under any circumstances.
I've also tried to get the same result by setting the android:tint property on the <ImageView/>, but apparently you cannot use a reference to a <selector> there, since it throws a NumberFormatException.
I don't see what I'm doing wrong so any help would be appreciated.
OK, I never got the above code to work, so here's what I ended up doing.
First, I subclassed LayerDrawable:
public class StateDrawable extends LayerDrawable {
public StateDrawable(Drawable[] layers) {
super(layers);
}
#Override
protected boolean onStateChange(int[] states) {
for (int state : states) {
if (state == android.R.attr.state_selected) {
super.setColorFilter(Color.argb(255, 255, 195, 0), PorterDuff.Mode.SRC_ATOP);
} else {
super.setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_ATOP);
}
}
return super.onStateChange(states);
}
#Override
public boolean isStateful() {
return true;
}
}
I changed the buildTab() method to the following:
private View buildTab(int icon, int label) {
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.tab_button, null);
((ImageView) view.findViewById(R.id.tab_icon)).setImageDrawable(new StateDrawable(new Drawable[] { getResources()
.getDrawable(icon) }));
((TextView) view.findViewById(R.id.tab_text)).setText(getString(label));
return view;
}
I still add the tabs like this:
Intent fooIntent = new Intent().setClass(this, FooActivity.class);
tabHost.addTab(tabHost.newTabSpec(TAB_NAME_INFO).setIndicator(buildTab(R.drawable.tab_icon_info, R.string.info)).setContent(infoIntent));
This works for me, compatible with android 1.6.
Couldn't solve it with applying a colorfilter directly to the drawable either. What worked for me was getting the image as a Bitmap, create an empty second one with same measures, define a canvas for the second one, apply that colorfilter to a paint object and draw the first bitmap on the second one. Finally create a BitmapDrawable from the new Bitmap and you're done. Here is the code
ImageButton imageButton = (ImageButton)findViewById(R.id.aga);
Bitmap one = BitmapFactory.decodeResource(getResources(), R.drawable.pen_circle);
Bitmap oneCopy = Bitmap.createBitmap(one.getWidth(), one.getHeight(), Config.ARGB_8888);
Canvas c = new Canvas(oneCopy);
Paint p = new Paint();
p.setColorFilter(new LightingColorFilter(Color.CYAN, 1));
c.drawBitmap(one, 0, 0, p);
StateListDrawable states = new StateListDrawable();
states.addState(new int[] {android.R.attr.state_pressed}, new BitmapDrawable(oneCopy));
states.addState(new int[] { }, imageButton.getDrawable());
imageButton.setImageDrawable(states);
This is my class, hacked to support ColorFilter:
Usage:
final Drawable icon = getResources().getDrawable(iconResId);
final Drawable filteredIcon = // this is important
icon.getConstantState().newDrawable();
final FilterableStateListDrawable selectorDrawable =
new FilterableStateListDrawable();
selectorDrawable.addState(ICON_STATE_SELECTED, filteredIcon,
new PorterDuffColorFilter(mIconOverlayColor, PorterDuff.Mode.SRC_ATOP));
selectorDrawable.addState(ICON_STATE_DEFAULT, icon);
As you see the ColorFilter is not applied directly to the drawable, it is associated to it while adding a state to the selector Drawable.
What's important here is that
you need to create a new drawable from the constant state or you'll modify the constant state and thus any instance of that drawable around your activity.
you need to use my custom addState method, it has the same name of the framework method addState but I've added an additional argument (ColorFilter). This method does NOT exist in the framework superclass!
The code (dirty, but work for me):
/**
* This is an extension to {#link android.graphics.drawable.StateListDrawable} that workaround a bug not allowing
* to set a {#link android.graphics.ColorFilter} to the drawable in one of the states., it add a method
* {#link #addState(int[], android.graphics.drawable.Drawable, android.graphics.ColorFilter)} for that purpose.
*/
public class FilterableStateListDrawable extends StateListDrawable {
private int currIdx = -1;
private int childrenCount = 0;
private SparseArray<ColorFilter> filterMap;
public FilterableStateListDrawable() {
super();
filterMap = new SparseArray<ColorFilter>();
}
#Override
public void addState(int[] stateSet, Drawable drawable) {
super.addState(stateSet, drawable);
childrenCount++;
}
/**
* Same as {#link #addState(int[], android.graphics.drawable.Drawable)}, but allow to set a colorFilter associated to this Drawable.
*
* #param stateSet - An array of resource Ids to associate with the image.
* Switch to this image by calling setState().
* #param drawable -The image to show.
* #param colorFilter - The {#link android.graphics.ColorFilter} to apply to this state
*/
public void addState(int[] stateSet, Drawable drawable, ColorFilter colorFilter) {
// this is a new custom method, does not exist in parent class
int currChild = childrenCount;
addState(stateSet, drawable);
filterMap.put(currChild, colorFilter);
}
#Override
public boolean selectDrawable(int idx) {
if (currIdx != idx) {
setColorFilter(getColorFilterForIdx(idx));
}
boolean result = super.selectDrawable(idx);
// check if the drawable has been actually changed to the one I expect
if (getCurrent() != null) {
currIdx = result ? idx : currIdx;
if (!result) {
// it has not been changed, meaning, back to previous filter
setColorFilter(getColorFilterForIdx(currIdx));
}
} else if (getCurrent() == null) {
currIdx = -1;
setColorFilter(null);
}
return result;
}
private ColorFilter getColorFilterForIdx(int idx) {
return filterMap != null ? filterMap.get(idx) : null;
}
}
I've opened a bug about this: https://code.google.com/p/android/issues/detail?id=60183
UPDATE: the bug has been fixed in the framework, since Lollipop I think.
I think the fix commit is this: https://android.googlesource.com/platform/frameworks/base/+/729427d%5E!/
or on Github: https://github.com/android/platform_frameworks_base/commit/729427d451bc4d4d268335b8dc1ff6404bc1c91e
My workaround should still work after Lollipop, it just don't use the fix by Google.
Here is my variation of Mopper's code. The idea is that ImageView gets color filter when user touches it, and color filter is removed when user stops touching it.
class PressedEffectStateListDrawable extends StateListDrawable {
private int selectionColor;
public PressedEffectStateListDrawable(Drawable drawable, int selectionColor) {
super();
this.selectionColor = selectionColor;
addState(new int[] { android.R.attr.state_pressed }, drawable);
addState(new int[] {}, drawable);
}
#Override
protected boolean onStateChange(int[] states) {
boolean isStatePressedInArray = false;
for (int state : states) {
if (state == android.R.attr.state_pressed) {
isStatePressedInArray = true;
}
}
if (isStatePressedInArray) {
super.setColorFilter(selectionColor, PorterDuff.Mode.MULTIPLY);
} else {
super.clearColorFilter();
}
return super.onStateChange(states);
}
#Override
public boolean isStateful() {
return true;
}
}
usage:
Drawable drawable = new FastBitmapDrawable(bm);
imageView.setImageDrawable(new PressedEffectStateListDrawable(drawable, 0xFF33b5e5));
Here is my variation of #Malachiasz code, this lets you pick whatever combination of states and colors to apply to the base drawable.
public class ColorFilteredStateDrawable extends StateListDrawable {
private final int[][] states;
private final int[] colors;
public ColorFilteredStateDrawable(Drawable drawable, int[][] states, int[] colors) {
super();
drawable.mutate();
this.states = states;
this.colors = colors;
for (int i = 0; i < states.length; i++) {
addState(states[i], drawable);
}
}
#Override
protected boolean onStateChange(int[] states) {
if (this.states != null) {
for (int i = 0; i < this.states.length; i++) {
if (StateSet.stateSetMatches(this.states[i], states)) {
super.setColorFilter(this.colors[i], PorterDuff.Mode.MULTIPLY);
return super.onStateChange(states);
}
}
super.clearColorFilter();
}
return super.onStateChange(states);
}
#Override
public boolean isStateful() {
return true;
}
}

Categories