ChildViewのOnLongClickListenerは、ParentViewでOntouchListenerを無効にします
-
02-10-2019 - |
質問
を持っています AbsoluteLayout
それを持っています OnTouchListener
. 。このレイアウト内には、はるかに小さくあります LinearLayout
動的に配置されます。 OntouchListenerは、予想どおりに機能します。
これで、私が追加するときに問題が発生します LongClickListener
わたしの LinearLayout
. 。それは私を無効にします OnTouchListener
タッチがヒットした場合 LinearLayout
, 、しかし、それはまだトリガーされています LinearLayout
だった いいえ タッチにヒットします。
私のリスナー:
// listener on parent (AbsoluteLayout)
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.e("LOOOOGING");
mLinearLayout.getHitRect(mNoteRect);
mNoteRect.left += mX;
mNoteRect.top += mY;
mNoteRect.right = mNoteRect.left + mLinearLayout.getWidth();
mNoteRect.bottom = mNoteRect.top + mLinearLayout.getHeight();
if (mNoteRect.contains((int) event.getX(), (int) event.getY())) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mStartX = (int) event.getX() - mNoteRect.left;
mStartY = (int) event.getY() - mNoteRect.top;
return true;
}
mX = (int) event.getX() - mStartX;
mY = (int) event.getY() - mStartY;
setPadding(mX, mY, 0, 0);
return true;
}
return false;
}
});
// listener on child (LinearLayout)
mLinearLayout.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
// do something...
return true;
}
});
どうすればタッチを委任できますか LinearLayout
どこ OnLongClickListener
親に登録されていますか?
解決
OntouchListenerの内部で自分のLongClickの動作を構築しなければなりませんでした
private Handler mLongPressHandler = new Handler();
public final Runnable mDoLongPress = new Runnable() {
public void run() {
// do something
}
};
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mLinearLayout.getHitRect(mNoteRect);
mNoteRect.left += mX;
mNoteRect.top += mY;
mNoteRect.right = mNoteRect.left + mLinearLayout.getWidth();
mNoteRect.bottom = mNoteRect.top + mLinearLayout.getHeight();
if (mNoteRect.contains((int) event.getX(), (int) event.getY())) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mStartRawX = (int) event.getX();
mStartRawY = (int) event.getY();
mStartX = mStartRawX - mNoteRect.left;
mStartY = mStartRawY - mNoteRect.top;
mLongPressHandler.postDelayed(mDoLongPress, 1000);
return true;
}
mX = (int) event.getX() - mStartX;
mY = (int) event.getY() - mStartY;
if (event.getAction() == MotionEvent.ACTION_MOVE) {
if ((mStartRawX + 10 < (int) event.getX() || mStartRawX - 10 > (int) event.getX())
|| (mStartRawY + 10 < (int) event.getY() || mStartRawY - 10 > (int) event.getY())) {
mLongPressHandler.removeCallbacks(mDoLongPress);
}
}
if (event.getAction() == MotionEvent.ACTION_UP) {
mLongPressHandler.removeCallbacks(mDoLongPress);
}
setPadding(mX, mY, 0, 0);
return true;
}
return false;
}
});
他のヒント
このようなことを試しましたか?
// listener on child (LinearLayout)
mLinearLayout.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
AbsoluteLayout.requestFocus();
//do something else
return true;
}
});
私が読んだことから、タッチは焦点を獲得するのと同等です。 (UIイベントの処理)
編集:AbsoluteLayoutドキュメントをチェックすると、これが役立つかもしれません。 DispatchTouchEvent(MotionEventEV). 。それで遊んでみてください、から起動するように聞こえます Public Boolean OnLongClick(View V) 助けることができます
タッチスクリーンモーションイベントをターゲットビュー、またはターゲットの場合はこのビューを渡します。
onlongclick()からDispatchTouchevent()を送信するというMaraguesのアイデアは有望に見えましたが、DispatchTouchevent()に送信するためにイベントオブジェクトを構築する必要があります。
私はこれをめくって、親ビューでタッチイベントを傍受し、それを子ビューに転送しました。親ビューをサブクラス化してから、この方法を追加しました。
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// this allows us to catch touch events on the list view if a child button is in the same location, then pass them on to child buttons so they can use them, too
// we don't have to worry about move events because currently none of the child buttons use them
int touchX = Math.round(event.getX());
int touchY = Math.round(event.getY());
Rect touchRect = new Rect(touchX, touchY, touchX, touchY);
Log.d("onInterceptTouchEvent", "got touch at " + touchRect);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
for (View cell : ViewUtils.getSubviews(this)) {
int cellX = Math.round(cell.getX());
int cellY = Math.round(cell.getY());
Rect cellRect = new Rect(cellX, cellY, cellX + cell.getWidth(), cellY + cell.getHeight());
if (Rect.intersects(touchRect, cellRect)) {
for (View button : ViewUtils.getSubviews((ViewGroup) cell)) {
if (button instanceof ImageButton) {
int buttonX = Math.round(button.getX()) + cellX;
int buttonY = Math.round(button.getY()) + cellY;
Rect buttonRect = new Rect(buttonX, buttonY, buttonX + button.getWidth(), buttonY + button.getHeight());
Log.d("onInterceptTouchEvent", "found button at " + buttonRect);
if (Rect.intersects(touchRect, buttonRect)) {
Log.d("onInterceptTouchEvent", "forward touch to button");
button.dispatchTouchEvent(event);
break;
}
}
}
break;
}
}
break;
}
return true;
}
私の場合、親ビューはリストビューであり、子ビューはテーブルセル内の画像ビュートンです。したがって、このコードはテーブルセル、次に各セルのボタンを繰り返して、タッチの位置に一致するボタンを見つけて、タッチをそのボタンに転送します。私のボタンはすべて、OnClickListenerまたはOnLongClickListenerを使用するImageButtonsなので、Action_Moveイベントを転送するわけではありませんが、必要に応じてできます。
上記で使用したgetSubviews()メソッドは次のとおりです。
public static ArrayList<View> getSubviews(ViewGroup viewGroup) {
ArrayList<View> subviews = new ArrayList<View>();
for (int i=0; i<viewGroup.getChildCount(); i++) {
subviews.add(viewGroup.getChildAt(i));
}
return subviews;
}
更新:よりシンプルなバージョン
上記のコードは、親ビューのタッチを受信し、子どもビューを長くクリックする特定の状況に対応する必要があります。しかし、これは子どもの景色の定期的なクリックをサポートしていないことがわかりました。これは、OnInterceptTouchevent()が他のイベントを処理するのとは異なる方法でaction_downイベントを処理する方法に関連していると思います。 この方法のドキュメント とても混乱しています。
ただし、親または子のビューのいずれかで、あらゆる種類のタッチとクリックイベントをサポートする簡単なアプローチを次に示します。上記のように、これには親ビューをサブクラス化する必要があります。また、別のクラスでsetontouchListener()を使用するのではなく、そのクラスでOntouchメソッドを直接設定する必要があります。
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
this.onTouch(this, event); // send the touch to the onTouch method below
return false; // then let the touch proceed to child buttons
// return true = this method and this view's onTouch receives events; return false = this method and children's onTouch receive events; remove this method = only children's onTouch receive events
}
@Override
public boolean onTouch(View v, MotionEvent event) {
// work with this touch event here
return false; // then let the touch continue to other applicable views
// return true = only this view receives events; return false = this view and other applicable views receive events
}