Domanda

Ho un AbsoluteLayout che ha un OnTouchListener. All'interno di questo schema è un LinearLayout molto più piccolo posizionamento dinamico. L'OnTouchListener funziona come previsto.

Ora il problema arriva quando aggiungo un LongClickListener al mio LinearLayout. Questo disabilita la mia OnTouchListener se il tocco colpisce il LinearLayout, ma è ancora in gioco se il LinearLayout era non colpito dal tocco.

I miei ascoltatori:

// 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;
    }
});

Come posso delegare il tocco sul LinearLayout cui è registrato il OnLongClickListener, al genitore?

È stato utile?

Soluzione

ho dovuto costruire il mio comportamento longclick dentro la mia 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;
    }
});

Altri suggerimenti

Hai provato qualcosa di simile?

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

Da quello che ho letto, il tatto è equivalente a guadagnando attenzione. ( gestione eventi dell'interfaccia utente )

modifica: verifica della documentazione absoluteLayout, forse questo potrebbe aiutare: dispatchTouchEvent (MotionEvent ev) . Prova a giocare con essa, suona come il lancio dalla public boolean onLongClick (Visualizza v) potrebbe aiutare

Far passare l'evento touch screen movimento verso il basso per la visualizzazione di destinazione, o questo punto di vista, se è il bersaglio.

idea di Maragues inviare dispatchTouchEvent () da onLongClick () sembrava promettente, ma si sarebbe dovuto costruire un oggetto evento per inviare a dispatchTouchEvent () per simulare l'evento che è stato consumato dal OnLongClickListener.

I capovolto questo intorno a intercettare l'evento tocco nella vista padre, poi lo trasmette alla vista del bambino. Ho sottoclasse vista primaria, poi ha aggiunto questo metodo:

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

Nel mio caso, la vista padre è un ListView e il punto di vista del bambino sono ImageButtons all'interno delle celle della tabella. Quindi, questo codice un'iterazione celle della tabella, quindi i pulsanti in ogni cella, per trovare un pulsante corrispondente alla posizione tatto, e in avanti il ??tocco al pulsante. I miei tasti sono tutti ImageButtons che utilizzano OnClickListener o OnLongClickListener, quindi non mi inoltro eventi ACTION_MOVE, ma se si potrebbe necessario.

Ecco le getSubViews () metodo utilizzato in precedenza:

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

Aggiornamento: semplificare la Versione

Il codice di cui sopra dovrebbe funzionare per la situazione specifica di ricevere tocchi su una vista padre e click lungo su una visione del bambino. Ma ho scoperto che questo non supporta scatti regolari in vista dei bambini. Penso che questo è legato al modo in cui onInterceptTouchEvent () gestisce ACTION_DOWN eventi in modo diverso di quanto non gestisce altri eventi. Il documentazione per questo metodo è molto confuso.

Comunque, ecco un approccio più semplice che dovrebbe supportare tutti i tipi di tocco e fare clic su eventi sia il genitore o il punto di vista del bambino. Come sopra, questo richiede sottoclasse della vista padre. Si richiede inoltre l'impostazione del metodo onTouch direttamente in quella classe piuttosto che usare setOnTouchListener () in un'altra classe:

@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
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top