我正在尝试使用MapView和ListView创建一个Activity。我使用C#和MonoDroid。
布局看起来像这样
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<app.MD.UI.PlacesMapView
android:id="@+id/mapView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:enabled="true"
android:clickable="true"
android:layout_weight="1"
android:apiKey="key" />
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:id="@+id/resultsTable" />
</LinearLayout>
我的自定义MapView类实现了长按处理程序
private void HandleLongPress(MotionEvent e)
{
if (e.Action == MotionEventActions.Down) {
// Finger has touched screen.
longpressTimer = new Timer(LONGPRESS_THRESHOLD);
longpressTimer.AutoReset = false;
longpressTimer.Elapsed += delegate(object sender, ElapsedEventArgs e_elapsed) {
GeoPoint longpressLocation = Projection.FromPixels((int)e.GetX(), (int)e.GetY());
if (OnLongPress != null) {
OnMapViewLongPressEventArgs args = new OnMapViewLongPressEventArgs();
args.location = longpressLocation;
OnLongPress(this, args);
}
};
longpressTimer.Start();
lastMapCenter = MapCenter;
}
if (e.Action == MotionEventActions.Move) {
if (!MapCenter.Equals(lastMapCenter)) {
longpressTimer.Stop();
}
lastMapCenter = MapCenter;
}
if (e.Action == MotionEventActions.Up) {
// User has removed finger from map.
longpressTimer.Stop();
}
if (e.PointerCount > 1) {
// This is a multitouch event, probably zooming.
longpressTimer.Stop();
}
}
活动方法,它将标记添加到MapView
protected void AddPinToMap(GeoPoint location, string title, bool scrollTo, int zoom)
{
var pin = Resources.GetDrawable(Resource.Drawable.maps_pin);
PinOverlay pinOverlay = new PinOverlay(pin, this);
OverlayItem item = new OverlayItem(location, title, "");
pinOverlay.AddOverlay(item);
mapView.Overlays.Clear();
mapView.Overlays.Add(pinOverlay);
if (scrollTo) {
mapView.Controller.AnimateTo(location);
}
mapView.Controller.SetZoom(zoom);
}
这是我的PinOverlay课程
class PinOverlay : ItemizedOverlay
{
private List<OverlayItem> _items = new List<OverlayItem>();
private Context _context;
public PinOverlay(Drawable pin, Context context) : base(pin)
{
_context = context;
BoundCenterBottom(pin);
Populate();
}
protected override Java.Lang.Object CreateItem(int i)
{
return _items[i];
}
public override int Size()
{
return _items.Count();
}
public void AddOverlay(OverlayItem overlay) {
_items.Add(overlay);
Populate();
}
}
我的问题是,当我触摸MapView时,我的标记显示低于我触摸的点。 我认为这可能是因为我的MapView没有全屏显示。 当我删除ListView以便MapView可以占据整个屏幕时,我能够将标记放在我触摸屏幕的确切位置。
如果MapView只占用屏幕的一部分,有关如何处理触摸事件的任何建议或示例吗?
UPD 找到某种解决方法,仍然需要使用不同的屏幕尺寸进行测试
转换触摸坐标
public static Point ConvertCoordinates(Context context, MapView mapView, double x, double y)
{
var wm = context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
var display = wm.DefaultDisplay;
double diffY = (Convert.ToDouble(display.Height) / 2 - Convert.ToDouble(mapView.Height) / 2) / 2 - 20;
double diffX = Convert.ToDouble(display.Width) / 2 - Convert.ToDouble(mapView.Width) / 2;
Point size = new Point();
size.X = (int)(x - diffX);
size.Y = (int)(y - diffY);
return size;
}
像这样使用
var point = MapHelper.ConvertCoordinates(this.Context, this, e.GetX(), e.GetY());
GeoPoint longpressLocation = Projection.FromPixels(point.X, point.Y);
答案 0 :(得分:0)
你试过了吗?
public PinOverlay(Drawable pin, Context context)
: base(BoundCenterBottom(pin))
这会使你在地图上放置Drawable
点,而不是在绘制时将地理坐标作为(x,y)(0,0)坐标。
修改强>
我似乎无法在这里重新创建你的问题,当在构造函数的:base()
中使用BoundCenterBottom(pin)时,它使Drawable
居中很好。
我还注意到,在AddPinToMap
方法中,每次都会创建一个新的PinOverlay
。这不是必需的,您只需将新OverlayItem
添加到PinOverlay
,您只需向地图添加一次。如果要在地图中添加大量引脚,则效率更高,资源消耗更少。
所以看起来应该更像:
protected void AddPinToMap(GeoPoint location, string title, bool scrollTo, int zoom)
{
var pin = Resources.GetDrawable(Resource.Drawable.maps_pin);
OverlayItem item = new OverlayItem(location, title, "");
pinOverlay.AddOverlay(item); // this is instantiated in OnCreate
if (scrollTo) {
mapView.Controller.AnimateTo(location);
}
mapView.Controller.SetZoom(zoom);
}
如果您希望能够删除Remove
,请向PinOverlay
添加OverlayItems
方法。
同样MapView
已经有LongClick
个事件,您可以将其挂钩而不是覆盖该类:
var mapView = FindViewById<MapView>(Resource.Id.myMapView);
mapView.LongClick += (sender, args) => { //do whatever in here };
或
var mapView = FindViewById<MapView>(Resource.Id.myMapView);
mapView.LongClick += OnLongClick;
private void OnLongClick(object sender, LongClickEventArgs longClickEventArgs)
{
// do whatever in here
}
答案 1 :(得分:0)
最后我找到了问题的原因。
这部分错误,因为在 Elapsed 委托中访问了 Projection 。但到那时Projection已经改变了它的状态,导致坐标错误。
if (e.Action == MotionEventActions.Down) {
// Finger has touched screen.
longpressTimer = new Timer(LONGPRESS_THRESHOLD);
longpressTimer.AutoReset = false;
longpressTimer.Elapsed += delegate(object sender, ElapsedEventArgs e_elapsed) {
GeoPoint longpressLocation = Projection.FromPixels((int)e.GetX(), (int)e.GetY());
if (OnLongPress != null) {
OnMapViewLongPressEventArgs args = new OnMapViewLongPressEventArgs();
args.location = longpressLocation;
OnLongPress(this, args);
}
};
longpressTimer.Start();
lastMapCenter = MapCenter;
}
因此,解决方案是在 OnTouchEvent 的最开始时获取 GeoPoint 。
if (e.Action == MotionEventActions.Down) {
capturedProjection = Projection.FromPixels((int)e.GetX(), (int)e.GetY());
// Finger has touched screen.
longpressTimer = new Timer(LONGPRESS_THRESHOLD);
longpressTimer.AutoReset = false;
longpressTimer.Elapsed += (object sender, ElapsedEventArgs e_timer) => {
if (OnLongPress != null) {
OnMapViewLongPressEventArgs args = new OnMapViewLongPressEventArgs();
args.location = capturedProjection;
OnLongPress(this, args);
}
};
longpressTimer.Start();
lastMapCenter = MapCenter;
}