Zoomlayout: 双击放大

创建于 2017-09-29  ·  13评论  ·  资料来源: natario1/ZoomLayout

对双击以控制缩放做出反应是很常见的。 这应该是ZoomEngine中的可选功能,默认情况下在ZoomImageView中启用。

enhancement long term

最有用的评论

你好,

关于如何通过双击实现缩放+平移的任何消息?

谢谢,
克里斯托夫

所有13条评论

@natario1

目前,我刚刚使用自定义手势侦听器类自行实现了此功能。 如果有人需要,这是我的代码片段。

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

            }
        };

然后将您的 touchlistener 分配给 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;
//        }
    }

请在覆盖 onScroll (必须)和其他方法(在我的情况下是可选的)上进行,因为它会与 ZoomImageView 的触摸事件冲突并产生问题。

希望这会帮助你。

我目前正在对双击以使事件完成的屏幕居中做出反应。

只需添加以下内容:

    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),但这几乎是相同的任务
  • 这应该可以通过一个至少有两个选项(“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()
    }
}

你好,

感谢您的努力! :)

这绝对看起来有点像实现它的hacky方式。 我认为我们现在会选择使用非常动画的动画。

谢谢,
尼古拉

你好,

关于如何通过双击实现缩放+平移的任何消息?

谢谢,
克里斯托夫

此页面是否有帮助?
0 / 5 - 0 等级