为什么视图层次结构会影响GestureDetector的行为?

时间:2013-01-04 07:29:58

标签: android

注意:我已更改此问题的原始标题。最初的标题是“如何一次使用几个GestureDetector实例?”,但我发现问题不是与几个探测器有关,而是与视图层次结构有关。问题的其余部分按原样保留,我决定不删除任何内容,只需阅读即可。请告知我是否应该废弃过时的零件,我已经准备好了,但不确定是否应该这样做。

我在另一个(容器)中有一个视图(按钮),我希望它们做两件事: 1)如果用户滚动任何视图(点击并移动),则滚动整个容器。 2)如果用户单击该按钮,则会为该按钮调用单击处理程序。

我的容器不是一个简单的视图,它允许在两个方向上滚动(here are the details),所以我设置了一个GestureDetector来检测滚动事件并滚动容器,感谢323go的建议。从附加到主容器视图的OnTouchListener的onTouch方法调用此检测器。

我的问题是按钮。

如果我设置onClick处理程序,它似乎完全吸收所有运动事件,所以如果我开始滚动按钮,我就无法滚动视图。

好的,也许我可以在按钮上设置另一个GestureDetector,以便处理点击和滚动?

不幸的是,这不起作用。按钮的onScroll处理程序在distanceX和distanceY参数中接收疯狂值。看起来容器视图和按钮都有自己的滚动计数器,因此当我滚动视图时,按钮会累积一些偏移量。

所以我的问题是:使用GestureDetector类的预期方式是什么?我可以在视图层次结构中使用多个检测器,是否可以将处理从一个检测器委托给另一个检测器?例如,如果孩子返回假,父母检测器可以处理该事件。

已添加:事实上,我对这样简单的“父对子”解决方案感到满意:在层次结构的最顶层视图中附加了唯一的GestureDetector,它接收所有事件并决定如何处理它们,所以如果它检测到滚动 - 它只是滚动整个视图而不通知任何人,但如果它检测到点击 - 它会在点击位置下方找到子视图并将点击转发给它。但这是一种真正的Android 方式吗?甚至可能吗?

进一步调查:我试图关注the advice given in comments below并让我的子手势检测器从其onScroll方法返回false。这没有帮助:如果子处理程序返回false,则根本不调用父处理程序。

但是我注意到如果子处理程序没有尝试滚动父视图,它将收到正确的值。

以下是我的处理程序的代码:

private class ParentHandler extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        Log.d("UI", "Parent Scroll X: " + String.valueOf(distanceX) + " Y: " + String.valueOf(distanceY));
        scrollBy((int)distanceX, (int)distanceY);
        return true;
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {return true;}

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {return true;}

    @Override
    public boolean onDown(MotionEvent e) {return true;}
};

private class ChildHandler extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        Log.d("UI", "Child Scroll X: " + String.valueOf(distanceX) + " Y: " + String.valueOf(distanceY));
        // The line below drives the handler crazy!
        // But if I remove it, the view will not be scrolled at all
        // because the parent handler is not called
        // even if this handler returned false.
        scrollBy((int)distanceX, (int)distanceY);
        return false;
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {return true;}

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {return true;}

    @Override
    public boolean onDown(MotionEvent e) {return true;}
};

注意第二个处理程序中的注释。

如果删除了疯狂的电话,以下是我在日志中获得的内容:

Parent Scroll X: -1.0 Y: 2.0
Parent Scroll X: 0.0 Y: 2.0
Parent Scroll X: -1.0 Y: 1.0
Parent Scroll X: -1.0 Y: 2.0
Parent Scroll X: 0.0 Y: 2.0
...
Child Scroll X: -1.0 Y: 2.0
Child Scroll X: 0.0 Y: 2.0
Child Scroll X: -1.0 Y: 1.0
Child Scroll X: -1.0 Y: 2.0
Child Scroll X: 0.0 Y: 2.0

但是当我尝试在子处理程序中移动视图时,值会变成这样的:

Child Scroll X: 13.0 Y: 22.0
Child Scroll X: -11.0 Y: -15.9999695
Child Scroll X: 11.0 Y: 17.00003
Child Scroll X: -10.0 Y: -16.00003
Child Scroll X: 11.0 Y: 19.99997

请注意,值是交替的:13后跟-11,下一个是11,然后是-10,依此类推。所以平均漂移似乎没问题,但是如果我只是将这些值传递给scrollBy调用,那么视图将会一直抖动并跳转到那里我一直在滚动它。

显然,在为子视图触发的onScroll中调用scrollBy存在一些问题。如果从父处理程序执行相同的调用,则没有问题。

那里可能有什么问题?

已添加:我已删除附加到父级的GestureDetector,但行为相同。

所以问题实际上如下。我需要在GestureDetector检测到滚动时滚动整个视图。要滚动视图,我调用scrollBy。如果为父视图触发了原始onTouch事件,则此方法有效,但如果为子视图触发了onTouch,则不会这样做:在后一种情况下,尝试滚动父视图会影响GestureHandler接收的值。

这样可行:

parent.onTouch - > detector.onTouchEvent - > parent.scrollBy

而这不是:

child.onTouch - > detector.onTouchEvent - > parent.scrollBy

其中探测器是相同的。

1 个答案:

答案 0 :(得分:2)

您可以创建一个侦听器,使用复合设计模式将事件转发给其他侦听器。

看一下这些帖子:

Attaching multiple listeners to views in android?

how can I set up multiple listeners for one event?