web-dev-qa-db-fra.com

Passage d'événements tactiles à la vue parent

J'ai un ViewSwitcher personnalisé dans lequel j'ai implémenté des événements tactiles afin que je puisse parcourir les écrans à l'aide de l'écran tactile.

Ma hiérarchie de présentation ressemble à ceci:

<ViewSwitcher>

    <LinearLayout>
        <ListView />
    </LinearLayout>

    <LinearLayout>
        <ListView />
    </LinearLayout>

</ViewSwitcher>

Maintenant, le problème est que les événements tactiles sont consommés par le ListViews et je ne suis pas en mesure de changer de vue. Cela fonctionne bien quand je n'ai pas le ListViews. Je dois pouvoir faire défiler les vues Et faire défiler la ListView.

Comment résoudre ce problème?

EDIT: J'ai également besoin des éléments ListView pour pouvoir être cliqués.

Merci d'avance!

34
Srichand Yella

Merci à tous d'avoir répondu à la question. Mais j'ai été capable de le comprendre d'une manière beaucoup plus simple. Comme ma ViewSwitcher ne détectait pas l'événement tactile, j'ai intercepté l'événement tactile, appelé onTouchEvent() et renvoyé false. Ici:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
    onTouchEvent(ev);
    return false;
}

En remplaçant le onInterceptTouchEvent(), j'ai pu intercepter l'événement tactile de l'activité. Ensuite, j'ai appelé onTouchEvent() dans la ViewSwitcher qui gère le basculement de la ListViews. Et enfin, en renvoyant false, il s'assure que ViewGroup ne consomme pas l'événement.

79
Srichand Yella

Le moyen le plus simple de passer d'une vue enfant à un événement tactile en vue parent consiste à l'ajouter à la vue enfant: 

@Override
public boolean onTouchEvent(MotionEvent event) { 
    super.onTouchEvent(event);
    return false;
}
8
macio.Jun

Dans ma présentation parente, le seul moyen que j'ai trouvé pour empêcher l'enfant de capturer l'événement tactile consiste à remplacer onInterceptTouchEvent par true. 

@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
    return true;
}
1
luca992

Je ne pense pas qu'il y ait un moyen facile pour vous de faire cela.

Ce n'est pas si compliqué, mais vous devrez créer votre propre vue qui étend la liste. Ensuite, vous pouvez remplacer le gestionnaire onTouch et décider (en fonction de l'événement touch) si vous souhaitez le gérer (et renvoyer la valeur true) ou le transmettre à la vue parent.

Le problème est aussi qu'une fois qu'un View gère un événement tactile, c'est celui qui récupérera tous les événements restants ...

À partir de documentation Android :

onTouch () - Ceci renvoie un booléen à indiquez si votre auditeur consomme cet événement. L'important La chose est que cet événement peut avoir plusieurs actions qui suivent chaque autre. Donc, si vous retournez false quand l'événement vers le bas est reçu, vous indique que vous n'avez pas consommé l'événement et ne sont pas non plus intéressés dans les actions ultérieures de cet événement . Ainsi, vous ne serez appelé pour aucun d'autres actions au sein de l'événement, telles que comme un geste du doigt, ou l'éventuel événement d'action

Ainsi, par exemple, si vous souhaitez un déplacement vertical pour faire défiler la liste et au cours du même événement tactile (sans lever le doigt), vous souhaitez un déplacement horizontal pour changer de vue, ce sera assez difficile.

Mais si vous pouvez utiliser des gestes par exemple ou tout gérer dans votre vue personnalisée et, en fonction de ce qu'est MotionEvent, envoyez des commandes à ViewSwitcher.

1
Matthieu

Vous pouvez également insérer un appel pour gérer touchevent dans dispatchTouchEvent, mais dans ce cas, vous devez également remplacer onTouchEvent pour renvoyer la valeur true, sinon seule la première MotionEvent DOWN du geste sera transmise.

Voici le conteneur d’emballage tactile:

<?xml version="1.0" encoding="utf-8"?>
<view xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/pager"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    class="com.example.myapp.FragmentContainer$TouchableWrapper" />

Et la classe:

public static class TouchableWrapper extends FrameLayout {
    private GestureDetector gestureDetector;
    public void setGestureDetector(GestureDetector gestureDetector) {
        this.gestureDetector = gestureDetector;
    }

    // these constructors for the XML inflater
    public TouchableWrapper(Context context) {
        super(context);
    }
    public TouchableWrapper(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public TouchableWrapper(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Log.d(TAG, "onInterceptTouchEvent " + event.toString());
        return false; // true for intercept, false è default and pass on to children View
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, "dispatchTouchEvent " + event.toString());
        gestureDetector.onTouchEvent(event);
        return super.dispatchTouchEvent(event);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent " + event.toString());
        return true; //return super.onTouchEvent(event); 
    }
}

Ceci est la référence GestureDetector:

private GestureDetector gestureDetector;

C'est la GestureListener:

private GestureDetector.SimpleOnGestureListener sOGL = new GestureDetector.SimpleOnGestureListener() {
    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        boolean result = false;
        try {
            float diffY = e2.getY() - e1.getY();
            float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        goToRight(); // onSwipeRight();
                    } else {
                        goToLeft(); // onSwipeLeft();
                    }
                }
                result = true;
            } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                if (diffY > 0) {
                    // onSwipeBottom();
                } else {
                    // onSwipeTop();
                }
            }
            result = true;

        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return result; // return false indicate event not handled
    }
};

Ceci pour charger le fragment de conteneur pouvant être touché et un fragment contenu:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Log.d(TAG, "onCreateView()");
    View view = inflater.inflate(R.layout.fragmentcontainer, container, false);

    gestureDetector = new GestureDetector(view.getContext(), sOGL);
    ((FragmentContainer.TouchableWrapper) view).setGestureDetector(gestureDetector);

    FragmentManager fm = this.getFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.pager, frag).commit();

    return view;
}
0
Zanna

Si votre vue veut faire passer l'événement, assurez-vous de renvoyer false dans onTouchEvent. Sinon, la plate-forme pense que vous avez consommé l'événement et aucun traitement supplémentaire n'est nécessaire.

0
Steve Prentice

ce que j’ai fait est de définir un contactventlistener sur la liste dans le viewwitcher, gère l’événement, détecte l’action fling et appelle le metchod de viewswitcher. Ça marche.

0
Zephyr Yang

Il était nécessaire de manipuler le toucher dans TextView dans la vue parent avec autoLink = "trois"

private LinearLayout mParentView;
private TextView mTextView;
private View.OnTouchListener mParentListener = new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        ......
        return false;
    }
};
mParentView.setOnTouchListener(mParentListener);

mTextView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        mParentListener.onTouch(mParentView, event);
        return false;
    }
};
0

Avez-vous essayé de définir les éléments de liste comme non-cliquables comme ceci: Cela devrait propager l'événement click vers le haut.

0
SBerg413