onlongclickListener على Childview يعطل OnTouchListener على ParentView
-
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 الخاص بي
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;
}
});
من ما قرأته ، تعادل اللمس لكسب التركيز. ((التعامل مع أحداث واجهة المستخدم)
تحرير: التحقق من الوثائق المطلقة ، ربما يمكن أن يساعد هذا: DispatchTouchEvent (MotionEvent EV). حاول اللعب به ، يبدو مثل إطلاقه من منطقية عامة onlongclick (View V) يمكن ان تساعد
تمرير حدث Motion Screen Motion وصولاً إلى طريقة العرض الهدف ، أو طريقة العرض هذه إذا كان الهدف.
تبدو فكرة Maragues لإرسال DispatchTouchEvent () من Onlongclick () واعدة ، لكن عليك أن تبني كائن حدث لإرساله إلى DispatchTouchEvent () لتقليد الحدث الذي تم استهلاكه بواسطة onlongclickListener.
لقد انقلبت على هذا الحدث لاعتراض حدث اللمس في عرض الوالدين ، ثم أرسله إلى عرض الطفل. قمت بتصنيف طريقة عرض الوالدين ، ثم أضفت هذه الطريقة:
@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;
}
في حالتي ، فإن عرض الوالدين عبارة عن عرض قائمة وآراء الطفل هي ImageButtons داخل خلايا الجدول. لذلك يكرر هذا الرمز من خلال خلايا الجدول ، ثم الأزرار في كل خلية ، للعثور على زر يطابق موقع اللمس ، ويقوم بإعادة توجيه اللمس إلى هذا الزر. الأزرار الخاصة بي هي كلها ImageButtons التي تستخدم OnClickListener أو OnLongClickListener ، لذلك أنا لا أقوم بإعادة توجيه الأحداث 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;
}
تحديث: نسخة أبسط
يجب أن يعمل الرمز أعلاه من أجل الوضع المحدد لتلقي اللمسات على طريقة عرض الوالدين والنقرات الطويلة على عرض الطفل. لكنني وجدت أن هذا لا يدعم النقرات العادية في طرق عرض الطفل. أعتقد أن هذا مرتبط بالطريقة التي يتعامل بها OnInterceptOuChevent () مع الأحداث بشكل مختلف عن الأحداث الأخرى. ال وثائق لهذه الطريقة مربك للغاية.
ومع ذلك ، إليك طريقة أبسط يجب أن تدعم جميع أنواع اللمس والنقر فوق الأحداث في إما الوالد أو مشاهدات الطفل. على النحو الوارد أعلاه ، يتطلب هذا التصنيف الفرعي لعرض الوالدين. يتطلب أيضًا تعيين طريقة OnTouch مباشرة في تلك الفئة بدلاً من استخدام SetOnceListener () في فئة أخرى:
@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
}