iOS MKMapView 覆盖视图捕捉已选中touches/gestures
iOS MKMapView with overlay view catching selected touches/gestures
我正在尝试实现一个带有叠加视图的 MKMapView,它绘制一个可编辑的多边形。因此,我需要有选择地捕捉针对顶点的触摸手势,但让其他 touches/gestures 允许滚动和缩放地图。
那么我如何根据坐标以编程方式将选定的触摸发送到地图或叠加层?
以下代码将其归结为一个简化的场景:叠加视图在左侧为红色,在右侧为蓝色。一侧应捕获触摸事件,另一侧应允许地图交互。
map 和 overlay 都是 SuperView
:
上的子视图
public sealed class SuperView: UIView
{
readonly UIView map = new MapView();
readonly UIView overlay = new Overlay();
public SuperView()
{
AddSubview(map);
AddSubview(overlay);
}
public override UIView HitTest(CGPoint point, UIEvent uievent)
{
return point.X < Frame.Width / 2 ? map : overlay;
}
}
MapView
派生自 MKMapView
并且只确保允许滚动:
public sealed class MapView: MKMapView
{
public MapView() : base(UIScreen.MainScreen.Bounds)
{
ScrollEnabled = true;
}
}
Overlay
包含手势识别器并可视化两个区域:
public sealed class Overlay: UIView
{
public Overlay() : base(UIScreen.MainScreen.Bounds)
{
BackgroundColor = new UIColor(0, 0, 0, 0);
AddGestureRecognizer(new Recognizer());
}
public override void Draw(CGRect rect)
{
using (var context = UIGraphics.GetCurrentContext()) {
context.SetFillColor(new CGColor(1, 0, 0, 0.25f));
context.FillRect(new CGRect(rect.Left, rect.Top, rect.Width / 2, rect.Height));
context.SetFillColor(new CGColor(0, 0, 1, 0.25f));
context.FillRect(new CGRect(rect.Width / 2, rect.Top, rect.Width / 2, rect.Height));
}
}
}
识别器很直接:
public sealed class Recognizer: UIGestureRecognizer
{
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
Console.WriteLine("TouchesBegan");
base.TouchesBegan(touches, evt);
}
public override void TouchesMoved(NSSet touches, UIEvent evt)
{
Console.WriteLine("TouchesMoved");
base.TouchesMoved(touches, evt);
}
public override void TouchesEnded(NSSet touches, UIEvent evt)
{
Console.WriteLine("TouchesEnded");
base.TouchesEnded(touches, evt);
}
public override void TouchesCancelled(NSSet touches, UIEvent evt)
{
Console.WriteLine("TouchesCancelled");
base.TouchesCancelled(touches, evt);
}
}
生成的屏幕如下所示:
当触摸红色部分时,我希望与地图进行交互 - 但这是行不通的。
触摸蓝色部分时,我想查看手势识别器的控制台输出 - 这确实有效。
什么不起作用:
将叠加层调整为仅一半屏幕。
在这个人工示例中,这会有所帮助。但在我的真实应用程序中,触摸和非触摸之间的区别更加复杂。
将手势检测器添加到 MapView
。
自each gesture recognizer will receive touch events in a non-deterministic order以来,您永远不知道是地图还是手势检测器先接收到触摸事件。因此,即使触摸不应该接收到地图,地图也可能已经在滚动。
覆盖 HitTest
或 PointInside
.
我尝试覆盖 SuperView
、MapView
and/or Overlay
中的这些方法。但它们要么没有被调用,要么似乎没有任何作用。至少我可以防止手势识别器接收到红色区域的触摸。但它没有按预期到达地图。也许我做错了什么。但地图似乎忽略了转发的触摸。
我好像已经解决了上面描述的问题。显然,MKMapView
不应该是子视图,而需要是 ViewController
的 View
:
public sealed class SuperView: UIViewController
{
readonly UIView map = new MKMapView();
readonly UIView overlay = new Overlay();
public SuperView()
{
View = map;
map.AddSubview(overlay);
}
}
然后 Overlay
视图获得 HitTest
实现:
public override UIView HitTest(CGPoint point, UIEvent uievent)
{
return point.X < Frame.Width / 2 ? null : base.HitTest(point, uievent);
}
我正在尝试实现一个带有叠加视图的 MKMapView,它绘制一个可编辑的多边形。因此,我需要有选择地捕捉针对顶点的触摸手势,但让其他 touches/gestures 允许滚动和缩放地图。
那么我如何根据坐标以编程方式将选定的触摸发送到地图或叠加层?
以下代码将其归结为一个简化的场景:叠加视图在左侧为红色,在右侧为蓝色。一侧应捕获触摸事件,另一侧应允许地图交互。
map 和 overlay 都是 SuperView
:
public sealed class SuperView: UIView
{
readonly UIView map = new MapView();
readonly UIView overlay = new Overlay();
public SuperView()
{
AddSubview(map);
AddSubview(overlay);
}
public override UIView HitTest(CGPoint point, UIEvent uievent)
{
return point.X < Frame.Width / 2 ? map : overlay;
}
}
MapView
派生自 MKMapView
并且只确保允许滚动:
public sealed class MapView: MKMapView
{
public MapView() : base(UIScreen.MainScreen.Bounds)
{
ScrollEnabled = true;
}
}
Overlay
包含手势识别器并可视化两个区域:
public sealed class Overlay: UIView
{
public Overlay() : base(UIScreen.MainScreen.Bounds)
{
BackgroundColor = new UIColor(0, 0, 0, 0);
AddGestureRecognizer(new Recognizer());
}
public override void Draw(CGRect rect)
{
using (var context = UIGraphics.GetCurrentContext()) {
context.SetFillColor(new CGColor(1, 0, 0, 0.25f));
context.FillRect(new CGRect(rect.Left, rect.Top, rect.Width / 2, rect.Height));
context.SetFillColor(new CGColor(0, 0, 1, 0.25f));
context.FillRect(new CGRect(rect.Width / 2, rect.Top, rect.Width / 2, rect.Height));
}
}
}
识别器很直接:
public sealed class Recognizer: UIGestureRecognizer
{
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
Console.WriteLine("TouchesBegan");
base.TouchesBegan(touches, evt);
}
public override void TouchesMoved(NSSet touches, UIEvent evt)
{
Console.WriteLine("TouchesMoved");
base.TouchesMoved(touches, evt);
}
public override void TouchesEnded(NSSet touches, UIEvent evt)
{
Console.WriteLine("TouchesEnded");
base.TouchesEnded(touches, evt);
}
public override void TouchesCancelled(NSSet touches, UIEvent evt)
{
Console.WriteLine("TouchesCancelled");
base.TouchesCancelled(touches, evt);
}
}
生成的屏幕如下所示:
当触摸红色部分时,我希望与地图进行交互 - 但这是行不通的。 触摸蓝色部分时,我想查看手势识别器的控制台输出 - 这确实有效。
什么不起作用:
将叠加层调整为仅一半屏幕。
在这个人工示例中,这会有所帮助。但在我的真实应用程序中,触摸和非触摸之间的区别更加复杂。
将手势检测器添加到
MapView
。自each gesture recognizer will receive touch events in a non-deterministic order以来,您永远不知道是地图还是手势检测器先接收到触摸事件。因此,即使触摸不应该接收到地图,地图也可能已经在滚动。
覆盖
HitTest
或PointInside
.我尝试覆盖
SuperView
、MapView
and/orOverlay
中的这些方法。但它们要么没有被调用,要么似乎没有任何作用。至少我可以防止手势识别器接收到红色区域的触摸。但它没有按预期到达地图。也许我做错了什么。但地图似乎忽略了转发的触摸。
我好像已经解决了上面描述的问题。显然,MKMapView
不应该是子视图,而需要是 ViewController
的 View
:
public sealed class SuperView: UIViewController
{
readonly UIView map = new MKMapView();
readonly UIView overlay = new Overlay();
public SuperView()
{
View = map;
map.AddSubview(overlay);
}
}
然后 Overlay
视图获得 HitTest
实现:
public override UIView HitTest(CGPoint point, UIEvent uievent)
{
return point.X < Frame.Width / 2 ? null : base.HitTest(point, uievent);
}