我目前正在摆弄Android编程,但我在检测不同的触摸事件时遇到一个小问题,即正常触摸按下(按屏幕并立即释放),长按(触摸屏幕并按住手指放在上面)和动作(在屏幕上拖动)。
我想要做的是在屏幕上有一个图像(圆圈),我可以拖动它。然后,当我按一次(短/正常按下)时,Toast会提供一些关于它的基本信息。当我长按它时,会出现一个带有列表的AlertDialog来选择不同的图像(圆形,矩形或三角形)。
我使用自己的OnTouchListener创建了一个自定义视图来检测事件并在onDraw中绘制图像。 OnTouchListener.onTouch是这样的:
// has a touch press started?
private boolean touchStarted = false;
// co-ordinates of image
private int x, y;
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
touchStarted = true;
}
else if (action == MotionEvent.ACTION_MOVE) {
// movement: cancel the touch press
touchStarted = false;
x = event.getX();
y = event.getY();
invalidate(); // request draw
}
else if (action == MotionEvent.ACTION_UP) {
if (touchStarted) {
// touch press complete, show toast
Toast.makeText(v.getContext(), "Coords: " + x + ", " + y, 1000).show();
}
}
return true;
}
问题在于印刷机没有按预期工作,因为当我随意触摸屏幕时,它还会检测到一点点移动并取消触摸按压并在图像周围移动。
我“围攻”了一下我引入了一个新的变量“mTouchDelay”,我在ACTION_DOWN上设置为0,在MOVE中增加,如果在MOVE中它是> = 3,我执行我的“移动”代码。但我觉得这不是真正的方法。
我还没有发现如何检测长按。罪魁祸首真的是MOVE,似乎总是触发。
有关我大概需要的示例,请参阅Android应用程序“DailyStrip”:它显示漫画的图像。如果它对于屏幕而言太大,您可以拖动它。您可以点击一次以使某些控件弹出,并长按它以显示选项菜单。
PS。我试图让它在Android 1.5上运行,因为我的手机只运行1.5。
答案 0 :(得分:89)
此代码可以区分点击和移动(拖动,滚动)。在onTouchEvent中设置一个标志isOnClick,并在ACTION_DOWN上设置初始X,Y坐标。清除ACTION_MOVE上的标志(注意经常检测到无意识的移动,这可以通过THRESHOLD const来解决)。
private float mDownX;
private float mDownY;
private final float SCROLL_THRESHOLD = 10;
private boolean isOnClick;
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mDownX = ev.getX();
mDownY = ev.getY();
isOnClick = true;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (isOnClick) {
Log.i(LOG_TAG, "onClick ");
//TODO onClick code
}
break;
case MotionEvent.ACTION_MOVE:
if (isOnClick && (Math.abs(mDownX - ev.getX()) > SCROLL_THRESHOLD || Math.abs(mDownY - ev.getY()) > SCROLL_THRESHOLD)) {
Log.i(LOG_TAG, "movement detected");
isOnClick = false;
}
break;
default:
break;
}
return true;
}
对于LongPress,如上所述,GestureDetector是要走的路。检查此Q& A:
答案 1 :(得分:20)
来自Android文档 -
来自View.OnLongClickListener。当用户触摸并保持项目时(当处于触摸模式时)或者使用导航键或轨迹球聚焦于项目并按下并按住合适的“输入”键或按下并按住轨迹球时(一秒钟。
来自View.OnTouchListener。当用户执行限定为触摸事件的操作时调用此方法,包括按下,释放或屏幕上的任何移动手势(在项目的范围内)。
至于“即使我触摸时也会发生移动”,我会设置一个增量并确保在移动代码之前,视图已被移动了至少三角形。如果还没有,请启动触摸代码。
答案 2 :(得分:14)
在您的活动初始化中:
setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View view) {
activity.openContextMenu(view);
return true; // avoid extra click events
}
});
setOnTouch(new View.OnTouchListener(){
public boolean onTouch(View v, MotionEvent e){
switch(e.getAction & MotionEvent.ACTION_MASK){
// do drag/gesture processing.
}
// you MUST return false for ACTION_DOWN and ACTION_UP, for long click to work
// you can return true for ACTION_MOVEs that you consume.
// DOWN/UP are needed by the long click timer.
// if you want, you can consume the UP if you have made a drag - so that after
// a long drag, no long-click is generated.
return false;
}
});
setLongClickable(true);
答案 3 :(得分:3)
我正在寻找类似的解决方案,这就是我的建议。 在OnTouch方法中,记录MotionEvent.ACTION_DOWN事件的时间,然后为MotionEvent.ACTION_UP记录时间。这样您也可以设置自己的阈值。经过几次实验后,您将知道记录简单触摸所需的最大时间(毫秒),您可以根据自己的喜好使用移动或其他方法。
希望这有帮助。如果你使用了不同的方法并解决了你的问题,请发表评论。
答案 4 :(得分:3)
如果你需要在点击,长按和滚动之间分开使用GestureDetector
活动实施GestureDetector.OnGestureListener
然后在onCreate中创建检测器,例如
mDetector = new GestureDetectorCompat(getActivity().getApplicationContext(),this);
然后在View上选择setOnTouchListener(例如webview)
onTouch(View v, MotionEvent event) {
return mDetector.onTouchEvent(event);
}
现在你可以使用Override onScroll,onFling,showPress(检测长按)或onSingleTapUp(检测点击)
答案 5 :(得分:2)
我认为你应该实现GestureDetector.OnGestureListener 如Using GestureDetector to detect Long Touch, Double Tap, Scroll or other touch events in Android 和androidsnippets中所述 {{3}} 然后在onSingleTapUp中实现tap逻辑并在onScroll事件中移动逻辑
答案 6 :(得分:0)
我想在longclick没有以点击事件结束后处理这个烂摊子。
这就是我的所作所为。
public boolean onLongClick(View arg0) {
Toast.makeText(getContext(), "long click", Toast.LENGTH_SHORT).show();
longClicked = true;
return false;
}
public void onClick(View arg0) {
if(!longClicked){
Toast.makeText(getContext(), "click", Toast.LENGTH_SHORT).show();
}
longClick = false; // sets the clickability enabled
}
boolean longClicked = false;
这有点像黑客但它有效。
答案 7 :(得分:0)
它只需要覆盖类中的ontouch事件。检查一下,它帮助了我
答案 8 :(得分:0)
GestureDetector.SimpleOnGestureListener有三种方法可以提供帮助;
GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
//for single click event.
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
return true;
}
//for detecting a press event. Code for drag can be added here.
@Override
public void onShowPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clipData = ClipData.newPlainText("..", "...");
clipboardManager.setPrimaryClip(clipData);
ConceptDragShadowBuilder dragShadowBuilder = new CustomDragShadowBuilder(child);
// drag child view.
child.startDrag(clipData, dragShadowBuilder, child, 0);
}
//for detecting longpress event
@Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
}
});