カスタムビューのontouchメソッドでシングルタップタッチ検出が必要でした。 ACTION-DOWNとACTION-UPの両方とACTION-UPの両方でxとyの値を取得してみました。ACTIONDOWNとACTION-UPのXとYの値が等しい場合、シングルタップとして受け取るという条件を与えました。
私のコードは次のとおりです
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!mSupportsZoom && !mSupportsPan) return false;
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x; //here i get x and y values in action down
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
if (mSupportsPan && !mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
//mFocusX = mPosX;
//mFocusY = mPosY;
invalidate();
}
mLastTouchX = x;
mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP: {
final float x = ev.getX();
final float y = ev.getY();
touchupX=x; //here is get x and y values at action up
touchupY=y;
if(mLastTouchX == touchupX && mLastTouchY == touchupY){ //my condition if both the x and y values are same .
PinchZoomPanActivity2.tapped1(this.getContext(), 100); //my method if the singletap is detected
}
else{
}
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
しかし、私はそれを成し遂げることができません。つまり、すべてのアクションでメソッドが呼び出されます。 actionupとactiondownの両方のxとyの値が同じでなくても。また、画面上で指でタッチするときに、シングルタップの範囲を広げる必要があると思います。誰かが私にいくつかの方法を提案できますか?
私も最近同じ問題に遭遇し、それを機能させるためにデバウンスを実装しなければならなくなりました。理想的ではありませんが、もっと良いものが見つかるまではかなり信頼できます。
View.onClickListener の方がはるかに信頼性が高かったのですが、残念ながらOnTouchListenerからのMotionEventが必要です。
編集:ここで失敗する原因となる余分なコードを削除しました
class CustomView extends View {
private static long mDeBounce = 0;
static OnTouchListener listenerMotionEvent = new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if ( Math.abs(mDeBounce - motionEvent.getEventTime()) < 250) {
//Ignore if it's been less then 250ms since
//the item was last clicked
return true;
}
int intCurrentY = Math.round(motionEvent.getY());
int intCurrentX = Math.round(motionEvent.getX());
int intStartY = motionEvent.getHistorySize() > 0 ? Math.round(motionEvent.getHistoricalY(0)) : intCurrentY;
int intStartX = motionEvent.getHistorySize() > 0 ? Math.round(motionEvent.getHistoricalX(0)) : intCurrentX;
if ( (motionEvent.getAction() == MotionEvent.ACTION_UP) && (Math.abs(intCurrentX - intStartX) < 3) && (Math.abs(intCurrentY - intStartY) < 3) ) {
if ( mDeBounce > motionEvent.getDownTime() ) {
//Still got occasional duplicates without this
return true;
}
//Handle the click
mDeBounce = motionEvent.getEventTime();
return true;
}
return false;
}
};
}
Androidでシングルタップとダブルタップを検出するには、次の方法を使用しています。
class GestureTap extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.i("onDoubleTap :", "" + e.getAction());
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.i("onSingleTap :", "" + e.getAction());
return true;
}
}
GestureDetectorのコンストラクターで使用します。
detector = new GestureDetector(this, new GestureTap());
そして、onTouchリスナーに次のコードを追加します
@Override
public boolean onTouchEvent(MotionEvent event) {
detector.onTouchEvent(event);
return true;
}
完全を期すため、および他の誰かがここに到達した場合の回答を追加します。
GestureDetector
とOnTouchListener
を併用できます
final GestureDetector gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
//do something
return true;
}
@Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
}
@Override
public boolean onDoubleTap(MotionEvent e) {
return super.onDoubleTap(e);
}
});
viewToTouch.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
ビューにGestureDetector.SimpleOnGestureListenerを追加し、これにメソッドonSingleTapConfirmedを使用します。
このメソッドは、Android OSが特定のタッチがシングルタップで、ダブルタップではないであることを確認した場合にのみ呼び出されます。
Androidの例でグーグルできます。
はるかに単純で簡単な方法があります。 MotionEvent.ACTION_DOWN && MotionEvent.ACTION_UPを使用し、イベント間の違いのタイミングを計ります。
完全なコードはここにあります。 https://stackoverflow.com/a/15799372/3659481
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;
}
}
「等しい」演算子を使用する必要がないと考えてください。代わりに、おおよその値を使用します
case MotionEvent.ACTION_DOWN: {
final int CONST = 5;
final float x = ev.getX();
final float y = ev.getY();
mLastTouchXMax = x+CONST; //here i get x and y values in action down
mLastTouchXMin = x-CONST;
mLastTouchYMax = y+CONST;
mLastTouchYMin = y-CONST;
mActivePointerId = ev.getPointerId(0);
break;
}
ACTION_UPで、インターバル間のXとYの値を確認します。
float dX,dY,x,y;
tv.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP: //Event for On Click
if(x==view.getX() && y==view.getY()){
Toast.makeText(getApplicationContext(),"TextView Clicked",Toast.LENGTH_LONG).show();
}
break;
case MotionEvent.ACTION_DOWN:
x=view.getX();
y=view.getY();
dX = view.getX() - event.getRawX();
dY = view.getY() - event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
view.animate()
.x(event.getRawX() + dX)
.y(event.getRawY() + dY)
.setDuration(0)
.start();
break;
default:
return false;
}
return true;
}
});