Сенсорный сенсорный детектор в режиме Ontouch
Мне понадобилось обнаружение touch-touch в моем настраиваемом методе ontouch. Я попытался получить значения x и y как в ACTION-DOWN, так и в ACTION-UP, и в ACTION-UP я дал условие, что если значения X и Y в ACTIONDOWN и ACTION-UP равны, то возьмите их как один крайнюй.
Мой код выглядит следующим образом
@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;
}
но я не могу это сделать. Я имею в виду, что при каждом действии вызывается мой метод. даже когда значения x и y обоих действий и действий не совпадают. и я думаю, что мне также нужно поместить некоторый диапазон в синглет, когда мы касаемся пальцем по экрану. Может ли кто-нибудь предложить мне некоторые способы?
Ответы
Ответ 1
Я также столкнулся с той же проблемой в последнее время и в конечном итоге пришлось реализовать debounce, чтобы заставить его работать. Это не идеально, но он довольно надежный, пока я не смогу найти что-то лучше.
View.onClickListener был гораздо более надежным для меня, но, к сожалению, мне нужен MotionEvent от OnTouchListener.
Изменить: Удален избыточный код, который может привести к сбою здесь
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 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;
}
};
}
Ответ 2
Чтобы обнаружить Single и Double Tap в 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;
}
Ответ 3
Добавление ответа для полноты и если кто-то еще достигнет здесь:
Вы можете использовать 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);
}
});
Ответ 4
Добавить GestureDetector.SimpleOnGestureListener для представления и использования метода onSingleTapConfirmed.
Этот метод вызывается только тогда, когда ОС Android подтвердила, что касание конкретного объекта является одним нажатием, а не двойным нажатием.
Вы можете использовать Google для приложений для Android.
Ответ 5
Существует гораздо более простой и прямой путь.
Используйте MotionEvent.ACTION_DOWN && MotionEvent.ACTION_UP и выберите разницу между событиями.
Полный код можно найти здесь. fooobar.com/questions/102539/...
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;
}
}
Ответ 6
Думайте, что вам не нужно использовать "равный" оператор. Вместо этого используйте приблизительно значение
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 между интервалами.
Ответ 7
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;
}
});