سؤال

انا لدي 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
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top