Zoomlayout: ダブルタップしてズーム

作成日 2017年09月29日  ·  13コメント  ·  ソース: natario1/ZoomLayout

ズームを制御するためにダブルタップに反応するのが一般的です。 これはZoomEngineのオプトイン機能であり、$ ZoomImageViewでデフォルトで有効になっているはずです。

enhancement long term

最も参考になるコメント

こんにちは、

ダブルタップでズーム+パンを実現する方法に関するニュースはありますか?

ありがとう、
クリストフ

全てのコメント13件

@ natario1

今のところ、カスタムGestureListenerクラスを使用してこの機能を自分で実装しました。 誰かがそれを必要とするならば、これが私のコードスニペットです。

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

次に、これらの変数を初期化します。

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

            }
        };

次に、タッチリスナーをzoomimageviewオブジェクトに割り当てます。

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

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

ZoomImageViewのタッチイベントと競合して問題が発生するため、onScroll(MUST)およびその他のメソッド(私の場合はオプション)をオーバーライドしてください。

これがお役に立てば幸いです。

私は現在、イベントが行われた画面を中央に配置するためにダブルタップに反応しています。

これを追加するだけで:

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

今、私は正しく移動してズームしようとしています。 プルリクエストを機能させたい場合は、プルリクエストを開くことができます。

@AlvaroFalconかっこいい! 私はあなたにいくつかのヒントを与えることができます。

  • ZoomEngineには、スクロールとフリングに反応するジェスチャー検出器がすでにあります
  • onScale()内のロジックの99%を再利用できると思います。 スケールジェスチャの中心の座標で機能し、ズーム率を適用します。 ズーム係数を自分で割り当てる必要があります( zoomIn()は1.3を使用すると思います)が、それはほとんど同じタスクです
  • これは、少なくとも2つのオプション(「none」と「zoom」)を持つXML属性( doubleTapBehavior ?)を介して構成可能である必要があります。 デフォルトとしてnoneを使用して、すでにlibを使用しているユーザーに対してこれを変更しないようにします。

@ natario1かっこいい! 時間があればやります...

私は現在、ズームレイアウトを拡張するクラスを使用してプロジェクトで作業しているので、そこにロジックを追加します。
それを使って動きと同時にズームしようとしていますが、今のところ運が悪いです。

ヒントをありがとう!

moveTo()メソッドにアクションを追加できますか? それが終わった後に呼ばれるために、私はあなたが複数のことをすることができるようにそのようにもっと柔軟になると思います。

さて、moveTo、zoomBy、zoomToなどに...

次のようになります。

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

@AlvaroFalcon Kotlinではそうしますが、これはまだ純粋なJavaです。 ただし、将来的にはKotlinに移動します。 今のところ、誰でもアクセスできるonIdle()があります。

@AlvaroFalconズームとパンを同時に実現できましたか? コードを共有してもよろしいですか?

ダブルタップとピンチしてズームの両方を実装しました。 実用的なソリューションの鍵は、ズームレイアウト内のコンテンツビューにタップ/ダブルタップジェスチャ検出器を接続し、クリック可能な子がtrueになるようにズームレイアウトを構成することです。 次に、コンテンツビューのonTouchEventでtrueを返し、タッチイベントを消費して、ジェスチャ検出器に渡します。 そうすれば、ピンチ、ズーム、ダブルタップの両方が同時に機能します。 ダブルタップでズームインしても問題ありません。

ただし、ダブルタップされた領域にズームしようとしましたが、 ZoomEngine.moveToがどのように実装されているかを考えると、ズームとパンの同時補間は正しく動作せず、画像はさまざまなパスをスライドして目的地のズームとパン。 見た目は良くありませんが、何が起こっているのかわかりません。 補間アルゴリズムは、アニメーションの一部だけでなく、実際のズームが何であるかに基づいて、実際のパンを異なる方法で計算する必要があると思います。

ダブルタップされた領域にズームします

はい、それはまさに私がやろうとしてきたことです。 この@ natario1を行う方法に関する提案はありますか?

こんにちは@mman

また、ユーザーが画面をタップしたときに自動的にズームする方法と、終了位置に向かって渦巻くようにズームするためのアニメーションを実装しました。

このアニメーションを制御できれば、とても良いでしょう。あなたや他の人は、それをどうやって進めるかについての提案がありますか?

前もって感謝します :)

私はなんとか汚いハックでそれをすることができました。 私はズームエンジンをだまして、ピンチが起こっていると思い込ませています。

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

こんにちは、

努力してくれてありがとう! :)

それは間違いなくそれを達成するための少しハッキーな方法のように思えます。 ただし、今のところ、非常にアニメーション化されたアニメーションを使用することを選択すると思います。

ありがとう、
ニコライ

こんにちは、

ダブルタップでズーム+パンを実現する方法に関するニュースはありますか?

ありがとう、
クリストフ

このページは役に立ちましたか?
0 / 5 - 0 評価