对双击以控制缩放做出反应是很常见的。 这应该是ZoomEngine
中的可选功能,默认情况下在ZoomImageView
中启用。
@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),但这几乎是相同的任务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方式。 我认为我们现在会选择使用非常动画的动画。
谢谢,
尼古拉
你好,
关于如何通过双击实现缩放+平移的任何消息?
谢谢,
克里斯托夫
最有用的评论
你好,
关于如何通过双击实现缩放+平移的任何消息?
谢谢,
克里斯托夫