Question

J'ai un AbsoluteLayout qui a une OnTouchListener. Dans cette disposition il y a un LinearLayout beaucoup plus petit positionnement dynamique. Le OnTouchListener fonctionne comme prévu.

Maintenant, le problème vient quand j'ajouter un LongClickListener à mon LinearLayout. Cela désactive mon OnTouchListener si le contact touche le LinearLayout, mais il est encore en considération si le LinearLayout était pas touché par la touche.

Mes auditeurs:

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

Comment puis-je déléguer le contact sur le LinearLayout où le OnLongClickListener est inscrit, au parent?

Était-ce utile?

La solution

Je devais construire mon propre comportement longclick dans mon 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;
    }
});

Autres conseils

Avez-vous essayé quelque chose comme ça?

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

D'après ce que j'ai lu, le toucher est équivalent à obtenir le focus. ()

edit: vérification de la documentation AbsoluteLayout, cela pourrait peut-être aider: dispatchTouchEvent (MotionEvent ev) . Essayez de jouer avec elle, des sons comme le lancer de la public boolean onLongClick (Voir v) pourrait aider

passer l'événement de mouvement de l'écran tactile vers le bas à la vue cible, ou ce point de vue si elle est la cible.

L'idée de Maragues envoyer dispatchTouchEvent () de onLongClick () semblait prometteur, mais vous devez construire un objet d'événement pour envoyer à dispatchTouchEvent () pour mimer l'événement qui a été consommé par le OnLongClickListener.

Je renversé ce autour d'intercepter l'événement tactile dans la vue parent, puis le transmettre à la vue des enfants. Je le sous-classé vue parent, puis ajouté cette méthode:

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

Dans mon cas, la vue parent est un ListView et les vues de l'enfant sont ImageButtons à l'intérieur des cellules du tableau. Donc, ce code à travers les cellules itère de table, puis les boutons dans chaque cellule, pour trouver un bouton correspondant à l'emplacement de contact, et en avant la touche à ce bouton. Mes boutons sont tous ImageButtons qui utilisent OnClickListener ou OnLongClickListener, donc je ne suis pas la transmission des événements ACTION_MOVE, mais vous pouvez si nécessaire.

Voici la méthode getSubViews () utilisée ci-dessus:

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

Mise à jour: Version Simpler

Le code ci-dessus doit travailler pour la situation spécifique de recevoir des touches sur une vue parent et long clics sur une vue enfant. Mais je trouve que cela ne prend pas en charge dans les vues réguliers clics enfants. Je pense que cela est lié à la façon dont les poignées onInterceptTouchEvent () ACTION_DOWN événements différemment qu'il gère d'autres événements. Le est très déroutant.

Cependant, voici une approche plus simple qui devrait soutenir tous les types de contact et cliquez sur les événements dans le parent ou le point de vue de l'enfant. Comme ci-dessus, cela nécessite la vue sous-classement parent. Il faut aussi régler la méthode OnTouch directement dans cette classe plutôt que d'utiliser setOnTouchListener () dans une autre 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
}
scroll top