实际上,这确实是一个相当大的问题,因为UIScrollView 确实“吃”了TouchesMoved事件(即使传播了几个第一个事件)。
所以,我刚刚想出了直接从 UIWindow获取事件的方法。这肯定不是应用程序结构意义上的最佳方法,但在某些自定义情况下(这正是我所需要的)很好。
(示例在MonoTouch C#中)。
创建您的自定义 UIWindow(由于我的自定义逻辑(使用 MvvmCross 框架),我没有在这里展示如何用 MyWindow 替换标准 UIWindow,但这很容易并且通常在 appDelegate 初始化逻辑中完成 - 您会在 google/stack 溢出中发现):
public class MyWindow : UIWindow
{
public MyWindow(RectangleF bounds) : base(bounds)
{
}
public override void SendEvent(UIEvent evt)
{
if (evt.Type == UIEventType.Touches) {
var el = (UITouch)evt.AllTouches.AnyObject;
if (el.Phase == UITouchPhase.Began)
{
if(OnTouchBegan != null)
OnTouchBegan(el.View, new TouchCommandArgs(evt.AllTouches, evt));
}
if (el.Phase == UITouchPhase.Moved)
{
if(OnTouchMoved != null)
OnTouchMoved(el.View, new TouchCommandArgs(evt.AllTouches, evt));
}
if (el.Phase == UITouchPhase.Ended)
{
if(OnTouchEnd != null)
OnTouchEnd(el.View, new TouchCommandArgs(evt.AllTouches, evt));
}
if (el.Phase == UITouchPhase.Cancelled)
{
if(OnTouchCancel != null)
OnTouchCancel(el.View, new TouchCommandArgs(evt.AllTouches, evt));
}
} else
MvxTrace.Trace (evt.Type == null ? "-" : evt.ToString ());
base.SendEvent(evt);
}
public event TouchCommand OnTouchBegan;
public event TouchCommand OnTouchEnd;
public event TouchCommand OnTouchCancel;
public event TouchCommand OnTouchMoved;
}
public class TouchCommandArgs : EventArgs
{
public NSSet Touches { get; set; }
public UIEvent Evt { get; set; }
public TouchCommandArgs(NSSet touches, UIEvent evt)
{
Touches = touches;
Evt = evt;
}
}
并在处理事件的地方订阅自定义事件处理程序:
var window = (MyWindow) UIApplication.SharedApplication.KeyWindow;
window.OnTouchBegan += view_OnTouchBegan;
window.OnTouchMoved += view_OnTouchMoved;
window.OnTouchCancel += view_OnTouchCancel;
window.OnTouchEnd += view_OnTouchEnd;
像这样的处理程序(这都是你自己的):
void view_OnTouchBegan(object sender, TouchCommandArgs args)
{
// do your logic
}
在这种情况下,事件将同时处理(在两个地方:你的和 UIScrollView),所以如果你愿意,你可以取消窗口的事件传播,只有当你想阻止除你的之外的任何其他处理程序应用时(你可以添加“例如,处理程序的“已处理”标志)。