onTouchEvent ()에서 이동과 클릭을 구별하는 방법은 무엇입니까?
내 응용 프로그램에서 이동 및 클릭 이벤트를 모두 처리해야합니다.
클릭은 하나의 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;
}
});
아래 코드는 문제를 해결하는 것입니다
@ 우세하다 public boolean onTouchEvent (MotionEvent 이벤트) { 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)) { (dx> 0) 이동 (1); // 권리 이름은 (dx == 0) move (5); // 딸깍하는 소리 개체는 move (2); // 왼쪽 } 그밖에 { (dy> 0) 이동 (3); // 아래로 개체는 (dy == 0) move (5); // 딸깍하는 소리 개체는 move (4); //쪽으로 } } } 참을 반환하십시오. }
ACTION_MOVE가 발생하지 않고 ACTION_DOWN이 발생하는 것은 매우 어렵습니다. 첫 번째 터치가 위치와 다른 지점에서 화면에서 손가락을 조금만 움직이면 MOVE 이벤트가 트리거됩니다. 또한 MOVE 이벤트를 유발할 생각합니다. Action_Move 메소드에서 문을 사용하여 원래 DOWN 동작이 이동이 거리를 확인합니다. 이동이 일정 반경 밖에서 발생하면 MOVE 동작이 발생합니다. 아마도 최선의 자원 수단은 작동해야합니다.
클릭만으로 광고 다음을 사용하십시오.
if (event.getAction() == MotionEvent.ACTION_UP) {
}
위의 답변에 추가하면 onClick 및 Drag 작업을 모두 구현 후 코드를 사용할 수 있습니다. @Stimsoni의 도움을십시오.
// assumed all the variables are declared globally;
public boolean onTouch(View view, MotionEvent event) {
int MAX_CLICK_DURATION = 400;
int MAX_CLICK_DISTANCE = 5;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN: {
long clickDuration1 = Calendar.getInstance().getTimeInMillis() - startClickTime;
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) {
Toast.makeText(getApplicationContext(), "item clicked", Toast.LENGTH_SHORT).show();
Log.d("clicked", "On Item Clicked:: ");
// imageClickAction((ImageView) view,rl);
}
}
case MotionEvent.ACTION_MOVE:
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) {
//Toast.makeText(getApplicationContext(), "item clicked", Toast.LENGTH_SHORT).show();
// Log.d("clicked", "On Item Clicked:: ");
// imageClickAction((ImageView) view,rl);
}
else {
ClipData clipData = ClipData.newPlainText("", "");
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
//Toast.makeText(getApplicationContext(), "item dragged", Toast.LENGTH_SHORT).show();
view.startDrag(clipData, shadowBuilder, view, 0);
}
break;
}
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;
}
});
'ProgramingTip' 카테고리의 다른 글
트위터 부트가있는 전체 너비 레이아웃 (0) | 2020.11.06 |
---|---|
개행 또는 \ r \ n을 (0) | 2020.11.06 |
std :: string에 int 추가 (0) | 2020.11.06 |
시스템 파일 표시 / osx에서 git ignore 표시 (0) | 2020.11.06 |
파일 크기 형식 공급자 (0) | 2020.11.06 |