Zoomlayout: Zum Zoomen doppeltippen

Erstellt am 29. Sept. 2017  ·  13Kommentare  ·  Quelle: natario1/ZoomLayout

Es ist üblich, auf doppeltes Tippen zu reagieren, um den Zoom zu steuern. Dies sollte eine Opt-in-Funktion in ZoomEngine sein, die standardmäßig in ZoomImageView aktiviert ist.

enhancement long term

Hilfreichster Kommentar

Hallo,

Irgendwelche Neuigkeiten darüber, wie man Zoomen + Schwenken mit Doppeltippen erreichen kann?

Danke,
Christoph

Alle 13 Kommentare

@natario1

Im Moment habe ich diese Funktionalität gerade selbst mit der benutzerdefinierten Gesture Listener-Klasse implementiert. Hier ist mein Code-Snippet, falls jemand es braucht.

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

Initialisieren Sie dann diese Variablen:

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

            }
        };

Weisen Sie dann Ihren Touchlistener dem zoomimageview-Objekt zu:

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

und hier ist die Klasse 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;
//        }
    }

Bitte überschreiben Sie onScroll (MUSS) und andere Methoden (in meinem Fall optional), mit denen Sie nichts zu tun haben, da dies mit dem Touch-Ereignis von ZoomImageView in Konflikt steht und ein Problem verursacht.

Ich hoffe, das wird Ihnen helfen.

Ich reagiere derzeit auf Doppeltippen, um den Bildschirm dort zu zentrieren, wo das Ereignis durchgeführt wurde.

Einfach durch Hinzufügen von:

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

Jetzt versuche ich, mich richtig zu bewegen und zu zoomen. Ich kann eine Pull-Anfrage öffnen, wenn Sie möchten, dass es funktioniert.

@AlvaroFalcon das wäre cool! Ich kann dir ein paar Tipps geben.

  • Wir haben bereits einen Gestendetektor in ZoomEngine , der auf Scrollen und Schleudern reagiert
  • Ich denke, Sie können 99 % der Logik in onScale() wiederverwenden. Es arbeitet mit Koordinaten des Mittelpunkts der Skalengeste und wendet einen Zoomfaktor an. Sie müssten selbst einen Zoomfaktor zuweisen (ich denke, zoomIn() verwendet 1,3), aber es ist so ziemlich die gleiche Aufgabe
  • Dies sollte über ein XML-Attribut ( doubleTapBehavior ?) konfigurierbar sein, das mindestens zwei Optionen haben sollte ("none" und "zoom"). Lassen Sie uns none als Standard verwenden, damit wir dies nicht für diejenigen ändern, die die lib bereits verwenden.

@natario1 Cool! mach ich wenn ich zeit habe...

Ich arbeite derzeit in meinem Projekt mit einer Klasse, die Ihr Zoomlayout erweitert, also füge ich dort meine Logik hinzu.
Ich versuche, damit gleichzeitig mit Bewegung zu zoomen, aber im Moment kein Glück.

Danke für die Tipps!

Könnte eine Aktion in der Methode moveTo() hinzugefügt werden? Ich denke, dass es auf diese Weise flexibler wäre, angerufen zu werden, nachdem es beendet ist, sodass Sie mehrere Dinge tun können.

Nun, zu moveTo, zoomBy, zoomTo, etc...

Es könnte wie folgt sein:

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

@AlvaroFalcon In Kotlin würde ich das tun, aber das ist immer noch reines Java. Wir werden jedoch in Zukunft zu Kotlin wechseln. Im Moment gibt es onIdle() , auf das jeder zugreifen kann.

@AlvaroFalcon konnten Sie gleichzeitig zoomen und schwenken? etwas dagegen, deinen Code zu teilen?

Ich habe sowohl Double Tap als auch Pinch to Zoom implementiert. Der Schlüssel zur funktionierenden Lösung besteht darin, den Tap/Double-Tap-Gestendetektor an die Inhaltsansicht innerhalb des Zoom-Layouts anzufügen und das Zoom-Layout so zu konfigurieren, dass anklickbare untergeordnete Elemente auf „True“ gesetzt werden. Geben Sie dann im onTouchEvent der Inhaltsansicht true zurück, um Berührungsereignisse zu konsumieren und sie an den Gestendetektor zu übergeben. Auf diese Weise funktionieren Pinch, Zoom und Double Tap gleichzeitig. Zoomen per Doppelklick ist dann kein Problem.

Ich habe jedoch auch versucht, auf den Bereich zu zoomen, auf den doppelt getippt wurde, und angesichts der Art und Weise, wie ZoomEngine.moveTo implementiert ist, verhält sich die gleichzeitige Interpolation von Zoom und Pan nicht korrekt und das Bild rutscht auf verschiedenen Pfaden, um das zu erreichen Zoomen und Schwenken des Ziels. Es sieht optisch nicht ansprechend aus, aber ich bin nicht in der Lage herauszufinden, was passiert. Ich denke, der Interpolationsalgorithmus sollte den tatsächlichen Schwenk basierend auf dem tatsächlichen Zoom und nicht nur einem Bruchteil der Animation anders berechnen.

Zoomen Sie auf den Bereich, der doppelt angetippt wurde

Ja, genau das habe ich versucht. Irgendwelche Vorschläge, wie man das macht @natario1?

Hallo @mmann

Wir haben auch eine Möglichkeit implementiert, automatisch zu zoomen, wenn der Benutzer auf den Bildschirm tippt, und die Animation zum Zoomen in einer Art Wirbeln in Richtung der Endposition.

Es wäre sehr gut, wenn wir diese Animation steuern könnten - haben Sie oder andere Vorschläge, wie man das anstellen könnte?

Vielen Dank im Voraus :)

Ich habe es mit einem schmutzigen Hack geschafft. Ich trickse die Zoom-Engine aus, damit sie denkt, dass eine Prise stattfindet.

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()
    }
}

Hallo,

Danke für die Mühe! :)

Das scheint definitiv ein bisschen hacky zu sein, um es zu erreichen. Ich denke, wir werden uns jedoch dafür entscheiden, vorerst mit der sehr animierenden Animation zu leben.

Danke,
Nikolaj

Hallo,

Irgendwelche Neuigkeiten darüber, wie man Zoomen + Schwenken mit Doppeltippen erreichen kann?

Danke,
Christoph

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

aouledissa picture aouledissa  ·  10Kommentare

lucasrsv picture lucasrsv  ·  3Kommentare

kuoliangkwong picture kuoliangkwong  ·  4Kommentare

MohamedMedhat1998 picture MohamedMedhat1998  ·  6Kommentare

wakaztahir picture wakaztahir  ·  5Kommentare