示例应用程序(如下所示,我的添加内容)包含在Almeros library中。它允许用户执行多点触摸手势,以在不变的背景上移动,调整大小,旋转和推动对象:
我想实现一个长按一下监听器,但是显而易见(添加implements View.OnLongClickListener
并覆盖public boolean onLongClick(View v)
不起作用(永远不会调用该方法)。
我试图通过长按来将地球改为篮球(这两个图像已经包含在github上的示例中)。
我的问题:如何在保留库提供的现有手势功能的同时使用长按事件?
这是the sample code,其中包含少量添加内容(已使用20160326
标记)。
/**
* Test activity for testing the different GestureDetectors.
*
* @author Almer Thie (code.almeros.com)
* Copyright (c) 2013, Almer Thie (code.almeros.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
// 20170326 - Commented 1, Added 1
//public class TouchActivity extends Activity implements OnTouchListener {
public class TouchActivity extends AppCompatActivity implements View.OnTouchListener, View.OnLongClickListener {
private Matrix mMatrix = new Matrix();
private float mScaleFactor = .4f;
private float mRotationDegrees = 0.f;
private float mFocusX = 0.f;
private float mFocusY = 0.f;
private int mAlpha = 255;
private int mImageHeight, mImageWidth;
private ScaleGestureDetector mScaleDetector;
private RotateGestureDetector mRotateDetector;
private MoveGestureDetector mMoveDetector;
private ShoveGestureDetector mShoveDetector;
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Determine the center of the screen to center 'earth'
Display display = getWindowManager().getDefaultDisplay();
mFocusX = display.getWidth()/2f;
mFocusY = display.getHeight()/2f;
// Set this class as touchListener to the ImageView
ImageView view = (ImageView) findViewById(R.id.imageToMove);
view.setOnTouchListener(this);
//20160326 - Added 1
view.setOnLongClickListener(this);
// Determine dimensions of 'earth' image
Drawable d = this.getResources().getDrawable(R.drawable.earth);
mImageHeight = d.getIntrinsicHeight();
mImageWidth = d.getIntrinsicWidth();
// View is scaled and translated by matrix, so scale and translate initially
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
view.setImageMatrix(mMatrix);
// Setup Gesture Detectors
mScaleDetector = new ScaleGestureDetector(getApplicationContext(), new ScaleListener());
mRotateDetector = new RotateGestureDetector(getApplicationContext(), new RotateListener());
mMoveDetector = new MoveGestureDetector(getApplicationContext(), new MoveListener());
mShoveDetector = new ShoveGestureDetector(getApplicationContext(), new ShoveListener());
}
@SuppressWarnings("deprecation")
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
mRotateDetector.onTouchEvent(event);
mMoveDetector.onTouchEvent(event);
mShoveDetector.onTouchEvent(event);
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
mMatrix.reset();
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postRotate(mRotationDegrees, scaledImageCenterX, scaledImageCenterY);
mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
ImageView view = (ImageView) v;
view.setImageMatrix(mMatrix);
view.setAlpha(mAlpha);
return true; // indicate event was handled
}
// 20170326 - Added method
@Override
public boolean onLongClick(View v) {
Log.v("20170326", "onLongClick called <<<<<<<<<<<<<<<<<<<<<<<<<<<");
ImageView view = (ImageView) findViewById(R.id.imageToMove);
view.setImageDrawable(this.getResources().getDrawable(R.drawable.basketball));
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor(); // scale change since previous event
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
return true;
}
}
private class RotateListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
@Override
public boolean onRotate(RotateGestureDetector detector) {
mRotationDegrees -= detector.getRotationDegreesDelta();
return true;
}
}
private class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener {
@Override
public boolean onMove(MoveGestureDetector detector) {
PointF d = detector.getFocusDelta();
mFocusX += d.x;
mFocusY += d.y;
// mFocusX = detector.getFocusX();
// mFocusY = detector.getFocusY();
return true;
}
}
private class ShoveListener extends ShoveGestureDetector.SimpleOnShoveGestureListener {
@Override
public boolean onShove(ShoveGestureDetector detector) {
mAlpha += detector.getShovePixelsDelta();
if (mAlpha > 255)
mAlpha = 255;
else if (mAlpha < 0)
mAlpha = 0;
return true;
}
}
}
答案 0 :(得分:1)
如用户mudit pant所示,同时拥有Touch
和Click
听众是个问题。因此,方法应该是使用原始sample code重新开始,并以与实现其他侦听器相同的方式实现LongPressListener
私有类:
// 20160327 - Added class
private class LongPressListener extends GestureDetector.SimpleOnGestureListener {
@Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
ImageView mView = (ImageView) findViewById(R.id.imageView);
mView.setImageDrawable(getApplicationContext().getResources().getDrawable(R.drawable.basketball));
}
}
然后,以同样的方式将其他检测器集成到onTouch()
方法中,添加新的监听器:
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
mRotateDetector.onTouchEvent(event);
mShoveDetector.onTouchEvent(event);
mMoveDetector.onTouchEvent(event);
// 20160327 - Added 1
mLongPressDetector.onTouchEvent(event);
.
.
.
}
同样地,在onCreate()
中创建另一个探测器:
public void onCreate(Bundle savedInstanceState) {
.
.
.
// Setup Gesture Detectors
.
.
.
// 20170327 - Added 1
mLongPressDetector = new GestureDetector(getApplicationContext(), new LongPressListener());
.
.
.
}
长按,图像变为篮球:
答案 1 :(得分:0)
问题是你有Touch和clicklisteners。触摸设备后立即调用触摸侦听器,并且由于您从那里返回true,因此此事件不会传播到单击侦听器。因此您的代码没有执行。处理此问题的最佳方法是在触摸时启动计时器以模仿长按行为。您应该在补足/移动事件中取消此计时器。如果您的计时器到期,那么长按事件就会起作用。希望这可以帮助。 :)
答案 2 :(得分:0)
answer here会触发不需要的长按事件。换句话说,如果用户使用的不仅仅是GestureDetector LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout()
,则会触发长按事件,即使用户可能只是试图移动或旋转或调整大小。快速移动工作正常,当他们试图获得精确时,长按事件会中断。我的第一个想法是增加超时,但它似乎是所有视图的系统范围,设置为500毫秒,并且不可自定义。
因此,非常简单且不需要或不使用GestureDetector
的备用解决方案是使用Handler.postDelayed()
和Runnable
。
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
mRotateDetector.onTouchEvent(event);
mMoveDetector.onTouchEvent(event);
mShoveDetector.onTouchEvent(event);
// 20170329 - removed 1, added 'if' block
//mLongPressDetector.onTouchEvent(event);
if(event.getAction() == MotionEvent.ACTION_DOWN) {
// Start a timer on each ACTION_DOWN
handler.postDelayed(mLongPressed, 1000);
}
.
.
.
}
在每个sample code onTouch()
方法中,计时器都会被删除。在除onMove()
之外的所有情况下,无条件地删除回调。但是在MoveListener的情况下,即使零偏移也会触发它。所以我只会在这里粘贴更改后的MoveListener,但是你需要在所有的监听器中放置handler.removeCallbacks(mLongPressed);
:
private class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener {
@Override
public boolean onMove(MoveGestureDetector detector) {
PointF d = detector.getFocusDelta();
mFocusX += d.x;
mFocusY += d.y;
// 20170329 - Added 'if' block - remove listener if there is non-zero offset
if ((d.x + d.y) != 0f) {
handler.removeCallbacks(mLongPressed);
Log.v(TAG, "onMove removed " + d.x + ", " + d.y);
}
return true;
}
}
最后,在您的活动中,您实例化Handler
并实施Runnable
// 20170329 - Added Handler and Runnable
final Handler handler = new Handler();
Runnable mLongPressed = new Runnable() {
public void run() {
Log.v(TAG, "mLongPressed Runnable triggered.");
ImageView mView = (ImageView) findViewById(R.id.imageView);
mView.setImageDrawable(getApplicationContext().getResources().getDrawable(R.drawable.basketball));
}
};
此解决方案来自this MSquare answer。