OnLongClickListener auf childView deaktiviert OnTouchListener auf parentView
-
02-10-2019 - |
Frage
ich eine AbsoluteLayout
haben, die eine OnTouchListener
hat. Innerhalb dieses Layouts gibt es einen viel kleineren LinearLayout
dynamisch positionierte. Die OnTouchListener wie erwartet funktioniert.
Jetzt kommt das Problem, wenn ich ein LongClickListener
meinen LinearLayout
hinzufügen. Das deaktiviert meine OnTouchListener
wenn die Berührung der LinearLayout
trifft, aber es ist immer noch ausgelöst, wenn die LinearLayout
war nicht Treffer durch Berührung.
Meine Zuhörer:
// 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;
}
});
Wie kann ich die Berührung auf dem LinearLayout
delegieren, wo der OnLongClickListener
registriert ist, an die Eltern?
Lösung
Ich hatte mein eigenes longclick Verhalten in meinem ontouchlistener
bauenprivate 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;
}
});
Andere Tipps
Haben Sie so etwas wie dies versucht?
// listener on child (LinearLayout)
mLinearLayout.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
AbsoluteLayout.requestFocus();
//do something else
return true;
}
});
Von dem, was ich gelesen habe, ist Touch-äquivalent Fokus zu gewinnen. ( Umgang UI Ereignisse )
edit: die absoluteLayout Dokumentation Überprüfung, vielleicht könnte dies helfen: dispatchTouchEvent (Motion ev) . Versuchen Sie, mit ihm zu spielen, klingt wie es startet von der public boolean onLongClick (Blick v) könnte helfen,
übergeben Sie das Touch-Screen-Bewegungsereignis bis auf die Zielansicht, oder diese Ansicht, wenn es das Ziel ist.
Maragues Idee dispatchTouchEvent () von onLongClick zu senden () schien vielversprechend, aber man müßte ein Ereignisobjekt baut das Ereignis dispatchTouchEvent (), um Mimik zu senden, die von der OnLongClickListener verbraucht wurde.
blätterte ich diese um zu Intercept des Berührungsereignis in der übergeordneten Ansicht, es dann zu der Ansicht, Kind weiterleiten. Ich subclassed die übergeordnete Ansicht, dann hinzugefügt, um diese Methode:
@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;
}
In meinem Fall ist die übergeordnete Ansicht ist ein Listview und das Kind Ansicht sind ImageButtons in den Tabellenzellen. Also dieser Code der Tabellenzellen durchläuft, dann in jeder Zelle der Tasten, eine Taste zu finden, die die Berührungsposition entspricht, und leitete die Verbindung zu dieser Taste. Meine Tasten sind alle ImageButtons die OnClickListener oder OnLongClickListener verwenden, so dass ich nicht ACTION_MOVE Ereignisse, aber man konnte, wenn nötig.
Hier ist das getSubViews () -Methode oben verwendet:
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;
}
Update: Einfachere Version
Der obige Code sollte für die spezifische Situation arbeiten von Berührungen auf einer übergeordneten Ansicht und lange Klicks auf einer untergeordneten Ansicht zu empfangen. Aber ich fand, dass dies nicht regelmäßig Klicks in den Kindern Ansichten unterstützt. Ich denke, dies ist die Art und Weise zusammenhängt, dass onInterceptTouchEvent () Griffe Ereignisse ACTION_DOWN anders als andere Ereignisse behandelt. Die Dokumentation für diese Methode ist sehr verwirrend.
Hier ist jedoch ein einfacher Ansatz, der alle Arten von Touch unterstützen sollten und klicken Sie auf Ereignisse in entweder die Eltern oder das Kind Blick. Wie oben erwähnt, erfordert dies Subklassen der übergeordneten Ansicht. Es erfordert auch die OnTouch Methode direkt in dieser Klasse Einstellung anstatt setOnTouchListener () in einer anderen Klasse:
@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
}