子视图上的OnLongClickListener在父视图上禁用了OnTouchListener

时间:2010-09-15 14:07:04

标签: android user-interface ontouchlistener onlongclicklistener

我的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注册的{{1}}上的联系人委托给父母?

3 个答案:

答案 0 :(得分:3)

我必须在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;
    }
});

答案 1 :(得分:1)

你尝试过这样的事吗?

   // listener on child (LinearLayout)
mLinearLayout.setOnLongClickListener(new OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        AbsoluteLayout.requestFocus();
        //do something else
        return true;
    }
});

从我读过的内容来看,触摸相当于获得焦点。 (handling UI events

编辑:检查absoluteLayout文档,这可能会有所帮助:dispatchTouchEvent(MotionEvent ev)。尝试使用它,听起来像从公共布尔值onLongClick(View v)启动它可以帮助

将触摸屏动画事件向下传递到目标视图,如果是目标视图则将此视图传递给该视图。

答案 2 :(得分:1)

Maragues从onLongClick()发送dispatchTouchEvent()的想法似乎很有希望,但你必须构建一个事件对象来发送到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;
}

在我的例子中,父视图是ListView,子视图是表格单元格内的ImageButtons。因此,此代码遍历表格单元格,然后遍历每个单元格中的按钮,以找到与触摸位置匹配的按钮,并将触摸转发到该按钮。我的按钮都是使用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事件的方式有关。 documentation for this method非常令人困惑。

但是,这是一种更简单的方法,应该支持父视图或子视图中的各种触摸和单击事件。如上所述,这需要子类化父视图。它还需要直接在该类中设置onTouch方法,而不是在另一个类中使用setOnTouchListener():

@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
}