【问题标题】:How to detect when any child view recieves a click如何检测任何子视图何时收到点击
【发布时间】:2018-05-17 00:00:03
【问题描述】:

给定具有任意子视图集合的任意 ViewGroup G,我如何检测用户何时单击任何子视图?在这种情况下,我想为 G 画一个高光。

我可以为每个孩子添加一个 onClick 侦听器,但我试图避免这种情况,以便在布局更改时不必更改代码。

或者,我可以将 onTouch 处理程序添加到 G 并在 ACTION_DOWN 期间设置突出显示。但是,这会触发实际上不会导致点击的操作,例如滑动(例如,滑动可以由 ViewPager 处理,最终与 G 无关)。

我的 G 布局具有可聚焦的属性:

android:focusable="true"
android:focusableInTouchMode="true"

谢谢。

【问题讨论】:

  • 首先:OnClicklistener 是 touchlistener 的一个实现,所以如果 onClick 不符合您的要求,那么您应该创建自己的。我建议看一下 View 的源代码,在那里你会发现 onTouchEvent 方法会调用 ClickListener (performClick())。第二:理论上应该可以确定是否应该将触摸事件分派到视图或视图分页器(onTouchIntercept)。准备弄脏你的手,这并不容易;)
  • 是的,onTouchEvent() 是所有点击等的基础。我认为看的正确位置是 AbsListView.onTouchUp()。有一个代码之谜可能正是我正在寻找的。​​span>

标签: android click focus


【解决方案1】:

这是我的做法:

//in onTouch method of parent, I get the coordinates of click
int x = ((int) motionEvent.getX());
int y = ((int) motionEvent.getY());

//obtain the clickable arrea of the child as HitRect
Rect clickRect = new Rect();
Rect rect = new Rect();
imageView.getHitRect(rect);

//ask if the area contains the coordinates of the click
if(rect.contains(x, y)){
    //do some work like if onClickListener on the child was called.
    return false; //you clicked here, don't need to handle other Childs
}

//ask for other childs like before...

现在,您可以将父级作为其内部完成的所有点击的代表,即使它是在子级中完成的。


编辑:

要忽略其他不是点击的触摸事件,您可以询问用户手指移动了多少:

case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_CANCEL:
     if (Math.abs(motionEvent.getRawX() - initialTouchX) > 5 || Math.abs(motionEvent.getRawY() - initialTouchY) > 5) {
              return true; // user mover finger too much, ignore touch
     }
     return false; // finger still there waiting for click

我给出一个 10 像素的正方形以允许舒适的点击,如果你退出它,我会忽略它。


额外:

这里是complete code,用于单击和长按 onTouchListener。

【讨论】:

  • 这种作品,但忽略了我的OP中的要求(见第3段)。
  • 我会为你的努力投赞成票,但我认为会有各种特殊情况失败。当然,可以继续微调来处理它们。自从我发布这个问题以来已经 4 年了,所以它在我的脑海中并不是很新鲜。再次感谢。
  • 我知道,我只是发布了答案,因为我一直在寻找它,经过一番搜索但没有弄清楚,我写了它并在这里发布以供将来的搜索者使用。
  • 有些事情没有处理,如果用户使用两根手指,但可以通过存储触摸 id 来解决。
【解决方案2】:

您可以使用 View.getChildCount() 循环遍历所有子视图并查看触摸是否与子视图相交。 这涉及获取 x 和 y 位置并计算它是否适合子视图,使用 View.getChildAt(position) 获取对子视图的引用。

所以应该是这样的:

int childNr = theView.getChildCount();
for (int i = 0; i < childNr; i++){
     YourView tmp = (YourView) theView.getChildAt(i);
     if(tmp.intersects(x, y)){
          do some work
     }
}

这里你必须放你的视图变量而不是 theView 和处理视图的类名而不是 (YourView) 和 x, y 是按下点的坐标。

【讨论】:

  • 也许我没有理解某些内容,但这如何帮助确定孩子何时发生点击?首先我需要知道点击发生了。然后,使用您的代码,我可以确定它发生的孩子。但我的问题是检测到点击。
  • 啊,是的,你总是需要一个 onClickListener。但它将是主视图的侦听器,而不是子视图。
  • 这似乎不起作用。我相信这是因为子视图正在消耗触摸事件。
  • 嗯,我认为这不应该发生,尝试在 onClickListener 中发出一条 logcat 消息,看看它是否被调用。
【解决方案3】:

在您的 XML 中,您可以将所有子项添加到同一个 onClick 方法。在该方法中,您可以将高光绘制到 G 上,然后为单个子视图执行某些操作(或不执行任何操作)。

【讨论】:

  • 这可能会起作用,假设一个视图可以有多个 onClick 处理程序。我希望有更好的解决方案:)
  • 不,任何一个视图都只有一个处理程序。但是多个视图可以共享同一个处理程序。在处理程序中,您可以确定单击了哪个视图(如果您关心的话)。
  • 对。我刚测试过。每个视图只有一个处理程序。所以这个解决方案没有帮助。在一个处理程序中收集所有点击将是一个可怕的混乱。感谢您的想法。
猜你喜欢
  • 2012-05-14
  • 1970-01-01
  • 2019-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-17
  • 1970-01-01
相关资源
最近更新 更多