Zoomlayout: Appuyez deux fois pour zoomer

Créé le 29 sept. 2017  ·  13Commentaires  ·  Source: natario1/ZoomLayout

Il est courant de réagir aux doubles pressions pour contrôler le zoom. Cela devrait être une fonctionnalité opt-in dans ZoomEngine , activée par défaut dans ZoomImageView .

enhancement long term

Commentaire le plus utile

Salut,

Des nouvelles sur la façon de réaliser un zoom + un panoramique sur un double tap ?

Merci,
Christophe

Tous les 13 commentaires

@natario1

Pour l'instant, je viens d'implémenter cette fonctionnalité par moi-même avec la classe Gesture Listener personnalisée. Voici mon extrait de code si quelqu'un en a besoin.

private GestureDetector gestureDetector; 
private View.OnTouchListener touchListener;
private ZoomImageView selectedImage;

puis initialisez ces variables :

    gestureDetector = new GestureDetector(mContext, new MyGestureListener());

        touchListener = new View.OnTouchListener() {
            <strong i="11">@Override</strong>
            public boolean onTouch(View v, MotionEvent event) {
                // pass the events to the gesture detector
                // a return value of true means the detector is handling it
                // a return value of false means the detector didn't
                // recognize the event
                selectedImage = (ZoomImageView) v;
                return gestureDetector.onTouchEvent(event);

            }
        };

puis assignez votre écouteur tactile à l'objet zoomimageview :

    ZoomImageView image = layout.findViewById(R.id.imageViewItemImageSlider);
    image.setOnTouchListener(touchListener);

et voici la classe MyGestureListener :

    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

//        <strong i="18">@Override</strong>
//        public boolean onDown(MotionEvent event) {
//            Log.d("TAG","onDown: ");
//
//            // don't return false here or else none of the other
//            // gestures will work
//            return true;
//        }
//
//        <strong i="19">@Override</strong>
//        public boolean onSingleTapConfirmed(MotionEvent e) {
//            Log.i("TAG", "onSingleTapConfirmed: ");
//            return true;
//        }
//
//        <strong i="20">@Override</strong>
//        public void onLongPress(MotionEvent e) {
//            Log.i("TAG", "onLongPress: ");
//        }

        <strong i="21">@Override</strong>
        public boolean onDoubleTap(MotionEvent e) {
            Log.i("TAG", "onDoubleTap: ");
            if((selectedImage.getEngine().getZoom() >= 2.75F)) {
                selectedImage.getEngine().zoomTo(1F, true);
            } else if((selectedImage.getEngine().getZoom() < 1F)) {
                selectedImage.getEngine().zoomTo(1F, true);
            }  else {
                selectedImage.getEngine().zoomBy(2F, true);
            }

            return true;
        }

//        <strong i="22">@Override</strong>
//        public boolean onScroll(MotionEvent e1, MotionEvent e2,
//                                float distanceX, float distanceY) {
//            Log.i("TAG", "onScroll: ");
//            return true;
//        }

//        <strong i="23">@Override</strong>
//        public boolean onFling(MotionEvent event1, MotionEvent event2,
//                               float velocityX, float velocityY) {
//            Log.d("TAG", "onFling: ");
//            return true;
//        }
    }

Veuillez remplacer onScroll (MUST) et une autre méthode (facultatif dans mon cas) que vous n'avez rien à gérer car cela entrera en conflit avec l'événement tactile de ZoomImageView et créera un problème.

J'espère que cela vous aidera.

Je réagis actuellement au double-clic pour centrer l'écran là où l'événement s'est déroulé.

Simplement en ajoutant ceci :

    private val simpleGestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {


        //here is the method for double tap


        override fun onDoubleTap(e: MotionEvent): Boolean {

            Log.d("OnDoubleTapListener", "onDoubleTap")
            centerElement(e.x.absoluteValue,e.y.absoluteValue)
            return true
        }

    })

    fun centerElement(clickedX: Float, clickedY: Float) {
        val offsetX = (width.absoluteValue) / 2
        val offsetY = (height.absoluteValue) / 2
        val displacedX = engine.panX.absoluteValue
        val displacedY = engine.panY.absoluteValue
        val x = (displacedX + clickedX / engine.realZoom) - (offsetX / engine.realZoom)
        val y = (displacedY + clickedY / engine.realZoom) - (offsetY / engine.realZoom)
        val desiredX = if (x > 0) -x else 0f
        val desiredY = if (y > 0) -y else 0f
        engine.moveTo(engine.zoom, desiredX, desiredY, true)
    }

Maintenant, j'essaie de me déplacer et de zoomer correctement. Je peux ouvrir une pull request si vous voulez que ça marche.

@AlvaroFalcon ce serait cool ! Je peux te donner quelques conseils.

  • Nous avons déjà un détecteur de gestes dans ZoomEngine qui réagit au défilement et au fling
  • Je pense que vous pouvez réutiliser 99% de la logique à l'intérieur onScale() . Il fonctionne avec les coordonnées du centre du geste d'échelle et applique un facteur de zoom. Vous auriez à attribuer vous-même un facteur de zoom (je pense que zoomIn() utilise 1,3) mais c'est à peu près la même tâche
  • Cela devrait être configurable via un attribut XML ( doubleTapBehavior ?) qui devrait avoir au moins deux options ("none" et "zoom"). Utilisons none par défaut afin de ne pas changer cela pour ceux qui utilisent déjà la bibliothèque.

@natario1 Cool ! Je le ferai quand j'aurai un peu de temps...

Je travaille actuellement dans mon projet avec une classe qui étend votre zoomlayout donc j'y ajoute ma logique.
J'essaie de faire un zoom avec mouvement en même temps en utilisant ça, mais pas de chance pour le moment.

Merci pour les conseils!

Une action pourrait-elle être ajoutée dans la méthode moveTo() ? Être appelé après qu'il soit terminé, je pense que ce serait plus flexible de cette façon afin que vous puissiez faire plusieurs choses.

Et bien, pour moveTo, zoomBy, zoomTo, etc...

Cela pourrait être comme:

moveTo(zoom, x, y, action : ()->Unit={})

@AlvaroFalcon Dans Kotlin, je le ferais, mais c'est toujours du pur Java. Nous passerons à Kotlin à l'avenir cependant. Pour l'instant, il y a onIdle() auquel tout le monde peut accéder.

@AlvaroFalcon avez-vous pu effectuer un zoom et un panoramique en même temps ? cela vous dérange de partager votre code ?

J'ai implémenté à la fois le double tapotement et le pincement pour zoomer. La clé de la solution de travail consiste à attacher le détecteur de gestes tap/double tap à la vue du contenu dans la disposition du zoom et à configurer la disposition du zoom pour que les enfants cliquables soient vrais. Ensuite, dans le onTouchEvent de la vue de contenu, renvoyez true pour consommer les événements tactiles et les transmettre au détecteur de gestes. De cette façon, le pincement, le zoom et le double tapotement fonctionnent en même temps. Zoomer sur le double tap n'est alors pas un problème.

Cependant, j'ai également essayé de zoomer sur la zone qui a été tapée deux fois, et compte tenu de la façon dont ZoomEngine.moveTo est implémenté, l'interpolation simultanée du zoom et du panoramique ne se comporte pas correctement et l'image glisse sur différents chemins pour atteindre le zoom et panoramique de la destination. Cela n'a pas l'air agréable visuellement, mais je n'arrive pas à comprendre ce qui se passe. Je pense que l'algorithme d'interpolation devrait calculer différemment le panoramique réel en fonction du zoom réel, et pas seulement de la fraction de l'animation.

zoomer sur la zone qui a été tapée deux fois

Oui, c'est exactement ce que j'ai essayé de faire. Des suggestions sur la façon de procéder @ natario1 ?

Salut @mman

Nous avons également mis en place un moyen de zoomer automatiquement lorsque l'utilisateur appuie sur l'écran et l'animation pour zoomer en sorte de tourbillonner vers la position finale.

Ce serait très bien si nous pouvions contrôler cette animation - est-ce que vous ou d'autres avez des suggestions sur la façon de procéder ?

Merci d'avance :)

J'ai réussi à le faire avec un sale hack. Je trompe le moteur de zoom en lui faisant croire qu'il y a un pincement.

class ReflectionHelper {
    <strong i="6">@Nullable</strong>
    static ScaleGestureDetector.OnScaleGestureListener getScaleDetectorListenerUsingReflection(ZoomEngine zoomEngine) {
        try {
            Field mScaleDetector = zoomEngine.getClass().getDeclaredField("mScaleDetector");
            mScaleDetector.setAccessible(true);
            ScaleGestureDetector detector = (ScaleGestureDetector) mScaleDetector.get(zoomEngine);
            Field mListener = detector.getClass().getDeclaredField("mListener");
            mListener.setAccessible(true);
            return (ScaleGestureDetector.OnScaleGestureListener) mListener.get(detector);
        } catch (Exception e) {
            return null;
        }
    }
}

private fun simulatePinch(fromScale: Float, toScale: Float, focusX: Float, focusY: Float) {
    class MockDetector(var mockScaleFactor: Float, var mockFocusX: Float, var mockFocusY: Float) : ScaleGestureDetector(context, null) {
        override fun getScaleFactor() = mockScaleFactor
        override fun getFocusX() = mockFocusX
        override fun getFocusY() = mockFocusY
    }

    val mockDetector = MockDetector(fromScale, focusX, focusY)
    ValueAnimator.ofFloat(fromScale, toScale).apply {
        addUpdateListener { animation ->
            mockDetector.mockScaleFactor = animation.animatedValue as Float
            zoomEngineScaleListener?.onScale(mockDetector)
        }
        doOnEnd { zoomEngineScaleListener?.onScaleEnd(mockDetector) }
        start()
    }
}

Salut,

Merci pour l'effort! :)

Cela semble définitivement être un moyen un peu hacky d'y parvenir. Je pense que nous choisirons cependant de vivre avec l'animation très animée pour l'instant.

Merci,
Nikolaj

Salut,

Des nouvelles sur la façon de réaliser un zoom + un panoramique sur un double tap ?

Merci,
Christophe

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

kuoliangkwong picture kuoliangkwong  ·  4Commentaires

aouledissa picture aouledissa  ·  10Commentaires

Yahor10 picture Yahor10  ·  5Commentaires

YiHaoHuang picture YiHaoHuang  ·  10Commentaires

wakaztahir picture wakaztahir  ·  5Commentaires