내 응용 프로그램에서 이동 및 클릭 이벤트를 모두 처리해야합니다.
클릭은 하나의 ACTION_DOWN 작업, 여러 ACTION_MOVE 작업 및 하나의 ACTION_UP 작업의 시퀀스입니다. 이론적으로 ACTION_DOWN 이벤트가 발생한 다음 ACTION_UP 이벤트가 발생하면 사용자가 방금보기를 클릭했음을 의미합니다.
그러나 실제로이 시퀀스는 일부 장치에서 작동하지 않습니다. 내 Samsung Galaxy Gio에서보기 : ACTION_DOWN, ACTION_MOVE, ACTION_UP을 여러 번 클릭하면 이러한 시퀀스가 나타납니다. 즉, ACTION_MOVE 액션 코드로 예상치 못한 OnTouchEvent가 발생합니다. ACTION_DOWN-> ACTION_UP 시퀀스를 전혀 (또는 거의) 얻지 않습니다.
또한 클릭 위치를 제공하지 않기 때문에 OnClickListener를 사용할 수 없습니다. 그렇다면 클릭 이벤트를 감지하고 이동과 어떻게 다릅니 까?
답변
여기에 매우 간단하고 손가락이 움직이는 것에 대해 걱정할 필요가없는 또 다른 솔루션이 있습니다. 단순히 이동 한 거리만큼 클릭을 기반으로하는 경우 클릭과 긴 클릭을 어떻게 구별 할 수 있습니까?
여기에 더 많은 스마트를 넣고 이동 한 거리를 포함 할 수 있지만, 사용자가 200 밀리 초 안에 이동할 수있는 거리가 클릭이 아닌 이동을 구성해야하는 경우를 아직 만나지 못했습니다.
setOnTouchListener(new OnTouchListener() {
private static final int MAX_CLICK_DURATION = 200;
private long startClickTime;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
startClickTime = Calendar.getInstance().getTimeInMillis();
break;
}
case MotionEvent.ACTION_UP: {
long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
if(clickDuration < MAX_CLICK_DURATION) {
//click event has occurred
}
}
}
return true;
}
});
답변
다음을 고려하여 최상의 결과를 얻었습니다.
- 주로 와 이벤트 간에 이동 한 거리 입니다. 다른 화면을 더 잘 지원하기 위해 최대 허용 거리를 픽셀이 아닌 밀도 독립형 픽셀 로 지정하고 싶었습니다 . 예 : 15 DP .
ACTION_DOWN
ACTION_UP
- 둘째, 이벤트 사이 의 기간 입니다. 1 초 는 최대로 보였습니다. (어떤 사람들은 아주 “엄청나게”, 즉 천천히 “클릭”합니다. 저는 여전히 그것을 인식하고 싶습니다.)
예:
/**
* Max allowed duration for a "click", in milliseconds.
*/
private static final int MAX_CLICK_DURATION = 1000;
/**
* Max allowed distance to move during a "click", in DP.
*/
private static final int MAX_CLICK_DISTANCE = 15;
private long pressStartTime;
private float pressedX;
private float pressedY;
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN: {
pressStartTime = System.currentTimeMillis();
pressedX = e.getX();
pressedY = e.getY();
break;
}
case MotionEvent.ACTION_UP: {
long pressDuration = System.currentTimeMillis() - pressStartTime;
if (pressDuration < MAX_CLICK_DURATION && distance(pressedX, pressedY, e.getX(), e.getY()) < MAX_CLICK_DISTANCE) {
// Click event has occurred
}
}
}
}
private static float distance(float x1, float y1, float x2, float y2) {
float dx = x1 - x2;
float dy = y1 - y2;
float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);
return pxToDp(distanceInPx);
}
private static float pxToDp(float px) {
return px / getResources().getDisplayMetrics().density;
}
여기의 아이디어는 Gem의 솔루션 과 동일하지만 다음과 같은 차이점이 있습니다.
- 이것은 두 점 사이 의 실제 유클리드 거리를 계산합니다 .
- 이것은 px 대신 dp를 사용합니다.
업데이트 (2015) : Gabriel의 미세 조정 된이 .
답변
촬영 Jonik의 우위를 내가 손가락을 이동 한 후 놓아 전에 자리로 돌아갈 경우 클릭으로 등록하지 않는 약간 더 미세 조정 버전을 내장 :
그래서 여기 내 해결책이 있습니다.
/**
* Max allowed duration for a "click", in milliseconds.
*/
private static final int MAX_CLICK_DURATION = 1000;
/**
* Max allowed distance to move during a "click", in DP.
*/
private static final int MAX_CLICK_DISTANCE = 15;
private long pressStartTime;
private float pressedX;
private float pressedY;
private boolean stayedWithinClickDistance;
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN: {
pressStartTime = System.currentTimeMillis();
pressedX = e.getX();
pressedY = e.getY();
stayedWithinClickDistance = true;
break;
}
case MotionEvent.ACTION_MOVE: {
if (stayedWithinClickDistance && distance(pressedX, pressedY, e.getX(), e.getY()) > MAX_CLICK_DISTANCE) {
stayedWithinClickDistance = false;
}
break;
}
case MotionEvent.ACTION_UP: {
long pressDuration = System.currentTimeMillis() - pressStartTime;
if (pressDuration < MAX_CLICK_DURATION && stayedWithinClickDistance) {
// Click event has occurred
}
}
}
}
private static float distance(float x1, float y1, float x2, float y2) {
float dx = x1 - x2;
float dy = y1 - y2;
float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);
return pxToDp(distanceInPx);
}
private static float pxToDp(float px) {
return px / getResources().getDisplayMetrics().density;
}
답변
감지기를 사용하면 작동하며 드래그시 상승하지 않습니다.
들:
private GestureDetector mTapDetector;
초기화 :
mTapDetector = new GestureDetector(context,new GestureTap());
이너 클래스 :
class GestureTap extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// TODO: handle tap here
return true;
}
}
onTouch :
@Override
public boolean onTouch(View v, MotionEvent event) {
mTapDetector.onTouchEvent(event);
return true;
}
즐겨 🙂
답변
클릭 이벤트 인식을 최적화하려면 다음 두 가지를 고려해야합니다.
- ACTION_DOWN과 ACTION_UP 사이의 시차입니다.
- 사용자가 터치 할 때와 손가락을 뗄 때의 x, y의 차이.
사실 저는 Stimsoni와 Neethirajan의 논리를 결합합니다.
그래서 여기 내 해결책이 있습니다.
view.setOnTouchListener(new OnTouchListener() {
private final int MAX_CLICK_DURATION = 400;
private final int MAX_CLICK_DISTANCE = 5;
private long startClickTime;
private float x1;
private float y1;
private float x2;
private float y2;
private float dx;
private float dy;
@Override
public boolean onTouch(View view, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
startClickTime = Calendar.getInstance().getTimeInMillis();
x1 = event.getX();
y1 = event.getY();
break;
}
case MotionEvent.ACTION_UP:
{
long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
x2 = event.getX();
y2 = event.getY();
dx = x2-x1;
dy = y2-y1;
if(clickDuration < MAX_CLICK_DURATION && dx < MAX_CLICK_DISTANCE && dy < MAX_CLICK_DISTANCE)
Log.v("","On Item Clicked:: ");
}
}
return false;
}
});
답변
길 SH 응답을 사용하여, 나는 구현하여 개선 onSingleTapUp()
보다는 onSingleTapConfirmed()
. 훨씬 더 빠르며 드래그 / 이동하면보기를 클릭하지 않습니다.
GestureTap :
public class GestureTap extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
button.performClick();
return true;
}
}
다음과 같이 사용하십시오.
final GestureDetector gestureDetector = new GestureDetector(getApplicationContext(), new GestureTap());
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
gestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_UP:
return true;
case MotionEvent.ACTION_MOVE:
return true;
}
return false;
}
});
답변
아래 코드는 문제를 해결할 것입니다
@우세하다 public boolean onTouchEvent (MotionEvent event) { switch (event.getAction ()) { case (MotionEvent.ACTION_DOWN) : x1 = event.getX (); y1 = event.getY (); 단절; case (MotionEvent.ACTION_UP) : { x2 = event.getX (); y2 = event.getY (); dx = x2-x1; dy = y2-y1; if (Math.abs (dx)> Math.abs (dy)) { if (dx> 0) move (1); //권리 그렇지 않으면 (dx == 0) move (5); //딸깍 하는 소리 그렇지 않으면 move (2); //왼쪽 } 그밖에 { if (dy> 0) move (3); // 아래로 그렇지 않으면 (dy == 0) move (5); //딸깍 하는 소리 그렇지 않으면 move (4); //쪽으로 } } } true를 반환하십시오. }