Windows Phone 7 - 使用 Rx 解释来自 TouchLocation 流的"double tap"



我有一个IObservable,我试图从它派生手势。

可以拉出"水龙头",但在"双击"的时候我的头很难绕起来。

TouchLocation有Position和State,所以Tap是根据两个条件聚合而来的。

1)位置在任何方向上移动不超过10px(允许一些移动,但不是拖动)

2)从状态为"按下"的事件开始,一直持续到状态为"释放"的事件进入

3)"释放"发生在"按下"后1秒内

现在我有一个IObservable>(聚合的结果),需要产生双击。

如何返回第一个手势(产生初始点击),然后将第二个手势替换为双击手势,但仅当在1秒计时器之前接收到第二个tap时。如果在计时器之后收到,那么它也应该是一个简单的Tap。

一个有趣的问题。

// Setup some parameters
var singleTapInterval = TimeSpan.FromSeconds(0.5);
var dblTapInterval = TimeSpan.FromSeconds(1);
// the source of touches
IObservable<TouchLocation> txs; 
// Get single taps
                               // 0, 1, but no more than 
                               // 2 touches in the timespan
IObservable<TouchLocation> taps = txs.Buffer(2,singleTapInterval) 
                                    .Where(touches => touches.Count == 2 &&
                                           touches[0].state == "Pressed" &&
                                           touches[1].state == "Released" &&
                                           distance(touches) < distanceThreshold)
                                    .Select(touches => touches[1]);
// now detect double taps
IObservable<TapKind> dbltaps = taps.Buffer(2,dblTapInterval)
                                   .Where(taps => taps.Count == 2)
                                   .Select(_ => TapKind.SingleTap);
// detect single taps - taps must be _slower_ than the dblTapInterval 
// for this to work
IObservable<TapKind> singletaps = taps.Throttle(dblTapInterval)
                                      .Select(_ => TapKind.SingleTap);
// compbine the two, so we see either tap condition
IObservable<TapKind> interestingTaps = dbltaps.Merge(singletaps);

我想我能给你的最好的答案是"不要那样做"。

XNA有一个内置机制来提供轻击、双击和其他手势。这些匹配系统范围内的手势行为,并且比实现自己的手势识别器要好得多。

有关如何使用内置手势功能的解释,请参阅MSDN上的此文档。这基本上是设置TouchPanel.EnabledGestures,轮询IsGestureAvailable,然后调用ReadGesture的情况。

回到开头,我意识到我把它弄得太复杂了……感谢斯科特帮我调整了方法!

"target"是一个IObservable(在一个扩展方法中)。

这个设置处理发送第一个事件(所以我们不失去第一个事件在zip等待),忽略了持有(水龙头需要超过1秒),取代了二锥与双击(但只有1秒内发生tap),覆盖一个新的要求,我不知道之前确保双击只遵循一个水龙头,从来没有另一个双击(4水龙头生产水龙头| DTap | DTap | DTap现在是利用| DTap |开发| DTap正确行为)

可能会简化一些,但这是重构前的工作版本:

var grouped = (from t in target
                group t by t.Id into groups
                select groups);
var presses = (from g in grouped
                from t in g
                where t.State == TouchLocationState.Pressed
                select t).Timestamp();
var releases = (from g in grouped
                from t in g
                where t.State == TouchLocationState.Released
                select t).Timestamp();
var pressAndRelease = presses.Zip(releases, (press, release) =>
    {
        return new { Press = press, Release = release };
    })
    .Where(pr =>
        {
            var delta = (pr.Release.Timestamp - pr.Press.Timestamp).TotalSeconds;
            return delta < 1;
        })
    .Timestamp();
var zipped = pressAndRelease.Zip(pressAndRelease.Skip(1), (prev, cur) =>
    {
        return new { Previous = prev, Current = cur };
    });
pressAndRelease.TakeUntil(zipped).Subscribe(a =>
    {
        Debug.WriteLine("FIRST TAP!");
    });
var wasDoubleTap = false;
zipped.Subscribe(a =>
    {
        var delta = (a.Current.Timestamp - a.Previous.Timestamp).TotalSeconds;
        if (wasDoubleTap || delta > 1)
        {
            Debug.WriteLine("TAP");
            wasDoubleTap = false;
        }
        else
        {
            Debug.WriteLine("DOUBLE TAP!");
            wasDoubleTap = true;
        }
    });

相关内容

  • 没有找到相关文章

最新更新