It´s possible that overlays on a map could receive focus from DPAD/Tab?
I have two fragments, a listview and mapview, I want to get focus from the drawable of the overlay, but I´m not sure if it´s possible...
Yes, you can move from one overlay item on MapView to other but there are few things which you should consider.
If you want your MapView to steer according to the Dpad directions while pressing up/down/left on Dpad, then your map will go up/down/left direction showing the map and you wont able to Dpad on overlay items since MapView is having the focus.
But if you want overlay items to be focused, then you have to manually define which overlay item it should focus on which D-Pad direction using setFocus, nextFocus and getFocus methods of ItemizedOverlay class.
Also you said you have listview and MapView in your activity and in order to get the focus back to listview or any other view which is outside MapView will also have to be done programmatically and it could be little tricky.
You can use StateListDrawable to define the different states on overlaid drawable for focus, pressed and default state.
Hope this answers your query.
I created a sample activity below. Most of the code comes from the MapView tutorial found here: http://developer.android.com/resources/tutorials/views/hello-mapview.html
The 'focus code' is in the onKeyDown() method. When TAB is pressed, focus is shifted to the next overlay. When ENTER is pressed, it shows a Toast, but that's where you can display your content.
The setFocus() method was found in the documentation for ItemizedOverlay found here: https://developers.google.com/maps/documentation/android/reference/
Hope this works.
public class OverlayFocusExampleActivity extends MapActivity {
private HelloItemizedOverlay itemizedoverlay;
private MapView mapView;
private MapController mapController;
private int currentOverlayIndex;
/*
* This entire method comes from the MapView tutorial.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapController = mapView.getController();
List<Overlay> mapOverlays = mapView.getOverlays();
// overlay_draw is a selector that specifies a different image for state_focused
Drawable drawable = this.getResources().getDrawable(R.drawable.overlay_draw);
itemizedoverlay = new HelloItemizedOverlay(drawable, this);
GeoPoint point = new GeoPoint(19240000, -99120000);
OverlayItem overlayitem = new OverlayItem(point, "Hola, Mundo!", "I'm in Mexico City!");
itemizedoverlay.addOverlay(overlayitem);
GeoPoint point2 = new GeoPoint(35410000, 139460000);
OverlayItem overlayitem2 = new OverlayItem(point2, "Sekai, konichiwa!", "I'm in Japan!");
itemizedoverlay.addOverlay(overlayitem2);
mapOverlays.add(itemizedoverlay);
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
OverlayItem overlay;
switch (keyCode) {
case KeyEvent.KEYCODE_TAB:
// Retrieve next overlay
currentOverlayIndex = (currentOverlayIndex + 1) % itemizedoverlay.size();
overlay = itemizedoverlay.getOverlayItem(currentOverlayIndex);
itemizedoverlay.setFocus(overlay);
// Since setFocus() doesn't center the map, we do it ourselves
mapController.animateTo(overlay.getPoint());
return true;
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
overlay = itemizedoverlay.getFocus();
if (overlay != null) {
// Perform associated action
// Stub
Toast.makeText(this, overlay.getSnippet(), Toast.LENGTH_SHORT).show();
return true;
}
default:
return false;
}
}
/*
* This entire class comes from the MapView tutorial except getOverlayItem().
*/
private class HelloItemizedOverlay extends ItemizedOverlay<OverlayItem> {
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
private Context mContext;
public HelloItemizedOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
}
public HelloItemizedOverlay(Drawable defaultMarker, Context context) {
super(boundCenterBottom(defaultMarker));
mContext = context;
}
public void addOverlay(OverlayItem overlay) {
mOverlays.add(overlay);
populate();
}
/*
* Not in MapView tutorial. Added for focusability.
*/
public OverlayItem getOverlayItem(int index) {
return mOverlays.get(index);
}
#Override
protected OverlayItem createItem(int i) {
return mOverlays.get(i);
}
#Override
public int size() {
return mOverlays.size();
}
#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;
}
}
}
Related
I use
+android 4.2
+osmdroid-android-3.0.9
+sherlock action bar
I need show on map item. On click at this item show dialog. But has trouble onItemSingleTapUp raised with offset.
osmapview = (MapView) findViewById(R.id.osmapview);
osmapview.setBuiltInZoomControls(true);
osmapview.setTileSource(TileSourceFactory.MAPNIK);
osmapview.setClickable(false);
final MapController mc = osmapview.getController();
mc.setZoom(14);
ArrayList<OverlayItem> overlayItems = new ArrayList<OverlayItem>();
CustomOverLay overlays = new CustomOverLay(overlayItems, getResources().getDrawable(R.drawable.marker96));
GeoPoint p = new GeoPoint(48.427677, 35.239871);
OverlayItem overlayItem = new OverlayItem("Title1", "Description1", p);
overlays.addItem(overlayItem);
public class CustomOverLay extends ItemizedIconOverlay<OverlayItem> {
public CustomOverLay(ArrayList<OverlayItem> overlayItems, Drawable drawable) {
super(overlayItems, drawable, new OnItemGestureListener<OverlayItem>() {
#Override
public boolean onItemSingleTapUp(final int index, final OverlayItem item) {
L.e("++" + 1);
return false;
}
#Override
public boolean onItemLongPress(final int index, final OverlayItem item) {
L.e("++" + 2);
return false;
}},
new DefaultResourceProxyImpl(getApplicationContext()));
}
#Override
protected boolean onSingleTapUpHelper(int index, OverlayItem item, MapView mapView) {
L.e("+ " + item.mTitle);
return super.onSingleTapUpHelper(index, item, mapView);
}
}
map drawed - ok
marker drawed - ok
tap on marker - failed
if tap bottom (very bottom) of marker - ok
What is the cause the offset?
Turn off hardware acceleration in your manifest or in code. See the samples application for examples on how to do this. There is better hardware acceleration support in 3.0.10.
It's error in osmdroid-android-3.0.9
use osmdroid-android-3.0.8
Issue
Somehow when I tap on the Icon I added to the Map the onTap Event is not called can somebody tell me why :S? Its a overlay with all Users I add to the Map they all have the same Icon but all diffrent Titles. But when I tap nothing happens I also tried Logging it if something happens with Log.d but nothing happens. This is the code:
private class MyUsersOverlay extends ItemizedOverlay<OverlayItem> {
private List<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
public MyUsersOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
}
#Override
protected OverlayItem createItem(int i) {
return mOverlays.get(i);
}
#Override
public int size() {
return mOverlays.size();
}
public void addOverlayItem(int lat, int lon, String title, String... message) {
GeoPoint point = new GeoPoint(lat, lon);
OverlayItem overlayItem = new OverlayItem(point, title, null);
addOverlayItem(overlayItem);
}
public void addOverlayItem(OverlayItem overlayItem) {
mOverlays.add(overlayItem);
populate();
}
#Override
protected boolean onTap(int index)
{
Log.d("Test Message", "It works");
OverlayItem item = mOverlays.get(index);
//Do stuff here when you tap, i.e. :
//AlertDialog.Builder dialog = new AlertDialog.Builder(cMainActivity);
//dialog.setTitle(item.getTitle());
//dialog.setMessage(item.getSnippet());
//dialog.show();
Toast.makeText(cMainActivity, item.getTitle(),
Toast.LENGTH_SHORT).show();
return true;
}
#Override
public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow)
{
super.draw(canvas, mapView, shadow);
if (shadow == false)
{
//cycle through all overlays
for (int index = 0; index < mOverlays.size(); index++)
{
OverlayItem item = mOverlays.get(index);
// Converts lat/lng-Point to coordinates on the screen
GeoPoint point = item.getPoint();
Point ptScreenCoord = new Point() ;
mapView.getProjection().toPixels(point, ptScreenCoord);
//Paint
Paint paint = new Paint();
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(10);
paint.setARGB(150, 0, 0, 0); // alpha, r, g, b (Black, semi see-through)
//show text to the right of the icon
canvas.drawText(item.getTitle(), ptScreenCoord.x, ptScreenCoord.y+10, paint);
}
}
}
Did you remember to put mapView.setClickable(true); in your oncreate() methode?
The problem isn't in the code above, but somewhere else. You have another view stealing the touch events from your ´ItemizedOverlay`.
Possibilities
You may be playing with dispatchTouchEvent() in your map activity and returning true all the time, informing that events have been used and no further dispatch should occour.
In the layout where you define MapView, you may have added a view after MapView that is parcialy covering it. Motion events are dispatched starting from last added view.
You may have added another MapView overlay that is covering the ItemizedOverlay.
It can be an issue if you want to click on an overlay AND have events for clicking on the general mapview. If that is what you are trying to achieve then check out this tutorial. Even if you are having a different issue the tutorial might help you fix your problem.
I am a beginner when it comes to working with the Maps API so please bear with me and I know there have been many other posts dealing with the same issue but I am still stuck.
I have been able to place some overlay images onto my map. The only issue I am having now is that I do not know how to make them disappear when I zoom out enough levels as this causes the overlay images to crowd together and overlap - basicaly making them useless at that level. So, any help on how to make them appear (after zoom level 18) would be truly appreciated.
I have tried using a zoom listener and an if statement but it had no change - most likely because I do not know where exactly I need to implement it and/or what other methods are required to enable it. Also, I am not sure on how to implement the draw() method as many others have used this to make it scale and disappear.
Edit:
These are the two classes I have so far which execute successfully (after applying the answer):
The Map.java file:
public class Map extends com.google.android.maps.MapActivity implements
OnOverlayGestureListener {
private boolean mShowOverlays = true;
private MapView mMapView;
MapView mapView;
MapController mapController;
private void setOverlayVisibility() {
boolean showOverlays = mMapView.getZoomLevel() > 18;
if (showOverlays != mShowOverlays) {
mShowOverlays = showOverlays;
for (Overlay overlay : mMapView.getOverlays()) {
if (overlay instanceof ItemOverlay) {
((ItemOverlay) overlay).setVisible(showOverlays);
}
}
}
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapController = mapView.getController();
mapController.setZoom(17);
boolean showOverlays = mMapView.getZoomLevel() > 18;
List<Overlay> mapOverlays = mapView.getOverlays();
Drawable lot = this.getResources().getDrawable(R.drawable.lot);
ItemOverlay parking_lot = new ItemOverlay(lot, this);
GeoPoint point1 = new GeoPoint(43806622, -79219797);
OverlayItem parking = new OverlayItem(point1, "Shopping Center","Parking Lot");
parking_lot.addOverlayItems(parking);
mapOverlays.add(parking_lot);
Drawable logo = this.getResources().getDrawable(R.drawable.entrance);
ItemOverlay ent = new ItemOverlay(logo, this);
GeoPoint start = new GeoPoint(43805697, -79221031);
mapController.setCenter(start);
OverlayItem welcome = new OverlayItem(start, "Welcome", " ");
ent.addOverlayItems(welcome);
mapOverlays.add(ent);
public <ZoomEvent> boolean onZoom(ZoomEvent ze, ManagedOverlay mo) {
setOverlayVisibility();
return true;
}
}
#Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
}
The ItemOverlay.java file:
public class ItemOverlay extends ItemizedOverlay<OverlayItem> {
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
private Context mContext;
private boolean visible = true;
private boolean mVisible = true;
public void setVisible(boolean value) {
mVisible = value;
}
public boolean isVisible() {
return mVisible ;
}
#Override
public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow) {
if (mVisible) {
super.draw(canvas, mapView, shadow);
}
}
public ItemOverlay(Drawable defaultMarker, Context context) {
super(boundCenterBottom(defaultMarker));
// TODO Auto-generated constructor stub
mContext = context;
}
public void addOverlayItems(OverlayItem overlay) {
mOverlays.add(overlay);
populate();
}
#Override
protected OverlayItem createItem(int i) {
// TODO Auto-generated method stub
return mOverlays.get(i);
}
#Override
public int size() {
// TODO Auto-generated method stub
return mOverlays.size();
}
#Override
protected boolean onTap(int index) {
// TODO Auto-generated method stub
OverlayItem item = mOverlays.get(index);
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
dialog.show();
return true;
}
}
I really like using the OverlayManager library for Android. It adds features to the Google Maps code, and makes a few things a lot easier. Find it here including some demo code that uses it
Option #1: If you use this, then you can use the OverlayManager's gesture listener interface for your MapActivity, to receive a callback for each zoom (in/out) event.
public class Map extends MapActivity implements OnOverlayGestureListener
{
private boolean mShowOverlays = true;
private MapView mMapView; // assign this in onCreate()
private void setOverlayVisibility() {
boolean showOverlays = mMapView.getZoomLevel() >= 18;
if (showOverlays != mShowOverlays) {
mShowOverlays = showOverlays;
for (Overlay overlay : mMapView.getOverlays()) {
if (overlay instanceof ItemOverlay) {
((ItemOverlay)overlay).setVisible(showOverlays);
}
}
}
}
// this is the onOverlayGestureListener callback:
public boolean onZoom(ZoomEvent ze, ManagedOverlay mo) {
setOverlayVisibility();
return true;
}
}
You will have to also add your Map instance as a gesture listener with ManagedOverlay.setOnOverlayGestureListener(). See the sample code for that.
Finally, in your ItemOverlay class, you can override the draw() method, and selectively draw based on whether the overlay has been marked as visible or not. You need to add a custom visible property:
public class ItemOverlay extends ItemizedOverlay {
private boolean mVisible = true;
public void setVisible(boolean value) {
mVisible = value;
}
public boolean isVisible() {
return mVisible ;
}
#Override
public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow) {
if (mVisible) {
super.draw(canvas, mapView, shadow);
}
}
}
Option #2: Now, using the Overlay Manager library just for this one purpose might be overkill. So, another, probably simpler alternative is to create a zoom listener in the way described in this stack overflow answer. The code Kurru provides would go in your Map class. You would replace this in the answer's code:
checkMapIcons();
with the method I showed above:
setOverlayVisibility();
So, now you have two ways to "watch" the zoom level, and overriding ItemOverlay.draw() allows you to make the markers disappear whenever you like (zoom level < 18 in this example).
I am trying to add a pin image to certain places to my map in my android application, but then there is a big semi transparent rectangle that appears over my map, that does not allow me to interact with the main map, I have tried using map overlay or itemized map overlay, but i get the same result, I dont know if this is because of the image, or this is usually what happens when someone adds an overlay to his map.
PS I am using a .png image
If anyone could help me i would be so grateful
thanks
this is the itemized overlay class
private class MirItemizedOverlay extends ItemizedOverlay {
private List<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
public MirItemizedOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
// TODO Auto-generated constructor stub
}
#Override
protected OverlayItem createItem(int i) {
return mOverlays.get(i);
}
#Override
public int size() {
return mOverlays.size();
}
public void addOverlayItem(OverlayItem overlayItem) {
mOverlays.add(overlayItem);
populate();
}
public void addOverlayItem(int lat, int lon, String title) {
GeoPoint point = new GeoPoint(lat, lon);
OverlayItem overlayItem = new OverlayItem(point, title, null);
addOverlayItem(overlayItem);
}
}
and this is how I use it in the oncreate method in my map activity
Drawable makerDefault =this.getResources().getDrawable(R.drawable.redcircle);
MirItemizedOverlay itemizedOverlay = new MirItemizedOverlay(makerDefault);
GeoPoint point = new GeoPoint((int) (49.9736518*1E6), (int) (7.114648 *1E6));
OverlayItem overlayItem = new OverlayItem(point, "hotspot1", null);
itemizedOverlay.addOverlayItem((int) (49.9736518*1E6), (int) (7.114648 *1E6), "hotspot1");
You should add your itemizedOverlay to MapView overlays:
MapView mapView = ...;
mapView.getOverlays().add(itemizedOverlay);
This code is using
the Google APIs (level 8).
When I update the OverlayItem to use a custom drawable the Canvas
object seems to draw the pixels in the wrong location. In this
example I'm trying to draw a circle in Louisiana. When viewing the
entire map the circle is drawn off the map. As you zoom into New
Orleans you'll see the circle approach the appropriate latitude and
longitude. The hot spot seems to be in the correct location, no
matter where the circle is being drawn.
If, in the draw method, the canvas restore method is called the circle
draws in the correct location.
Also If the custom drawable is not used, the icon is drawn in the
correct location (without using Canvas "restore").
Below is the code showing this behavior. I tried adding "setBounds"
and "boundCenterBottom", since other people seemed to indicate that
resolved their "wrong location" problems. Though
to be honest I'm not sure why those calls are needed.
=======================================================================
public class MapsActivity extends MapActivity
{
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MapView mapView = (MapView) findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
// Itemized Overlay
List<Overlay> mapOverlays = mapView.getOverlays();
Drawable defaultIcon =
this.getResources().getDrawable(R.drawable.icon);
MyItemizedOverlay itemizedoverlay = new
MyItemizedOverlay(defaultIcon, this);
// Overlay Item
GeoPoint pt = new GeoPoint(30000000, -90000000);
OverlayItem item = new OverlayItem(pt,"New Orleans",
"Louisiana");
// Custom Drawable
CustomDrawable customDrawable = new CustomDrawable(pt,
mapView);
boolean showProblem = true;
if (showProblem)
{
item.setMarker(customDrawable);
}
else
{
item.setMarker(defaultIcon);
}
// Add item we want to overlay
itemizedoverlay.addOverlay(item);
// Add overlay
mapOverlays.add(itemizedoverlay);
}
protected boolean isRouteDisplayed()
{
return false;
}
}
=======================================================================
public class MyItemizedOverlay extends ItemizedOverlay<OverlayItem>
{
private ArrayList<OverlayItem> mOverlays = new
ArrayList<OverlayItem>();
private Context mContext;
public MyItemizedOverlay(Drawable defaultMarker, Context context)
{
super(boundCenterBottom(defaultMarker));
mContext = context;
}
public void addOverlay(OverlayItem item)
{
mOverlays.add(item);
populate();
}
public void removeOverlay(OverlayItem item)
{
mOverlays.remove(item);
}
public void removeOverlay(int item)
{
mOverlays.remove(item);
}
protected OverlayItem createItem(int i)
{
OverlayItem item = mOverlays.get(i);
Drawable drawable = item.getMarker(0);
if (drawable != null)
{
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
drawable.setBounds(0, 0, w, h);
item.setMarker(boundCenterBottom(drawable));
}
return item;
}
public void draw(android.graphics.Canvas canvas, MapView mapView,
boolean shadow)
{
if (shadow)
return;
super.draw(canvas, mapView, shadow);
}
public int size()
{
return mOverlays.size();
}
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;
}
}
=======================================================================
public class CustomDrawable extends ShapeDrawable
{
private int radius = 10;
private GeoPoint point = null;
private MapView mapView = null;
public CustomDrawable(GeoPoint point, MapView mapView)
{
this.point = point;
this.mapView = mapView;
}
public void draw(Canvas canvas)
{
// TODO This (somewhat) fixes projection problem?
//canvas.restore();
Projection projection = mapView.getProjection();
Point pt = projection.toPixels(point, null);
canvas.drawCircle(pt.x, pt.y, radius,
getPaint());
}
public int getIntrinsicHeight()
{
return 2 * radius;
}
public int getIntrinsicWidth()
{
return 2 * radius;
}
}
=======================================================================
Your CustomDrawable shouldn't be positioning itself with respect to the map. It should just draw itself within its bounds, and not reference the MapView or its Projection. ItemizedOverlay takes care of positioning the Drawable for your OverlayItem.