Использовать ScaleGestureDetector с GestureDetector?

В моем приложении для Android у меня есть ImageView, где я хотел бы, чтобы пользователь мог бросить его влево/вправо/вверх/вниз, чтобы изменить изображение (статические карты) на соседнее. Но вдобавок хотелось бы возможности масштабирования щипком и саму карту.

Я могу заставить работать либо бросание, либо масштабирование, но не вместе. Я использую GestureDetectorSimpleOnGestureListener) для броска. И я использую ScaleGestureDetector (из Понимание мультитач) для масштабирования.

Трудность состоит в том, чтобы определить, какой слушатель жестов вызывать при касании. Это не проблема кодирования, а проблема логики. При касании одним пальцем это бросок или чешуя? Даже когда используется пинч-зум, начальный MotionEvent — это ACTION_DOWN. Я пытался использовать размер изображения (внутренний или масштабированный?) в качестве точки принятия решения. Но начальная операция масштабирования (когда размер изображения является внутренним, и я хочу увеличить его) с ACTION_DOWN, кажется, ускользает от меня.

Кто-нибудь успешно справлялся с этим ранее?


person mraviator    schedule 09.03.2013    source источник


Ответы (3)


Вы можете передавать события обоим детекторам жестов.

Проверьте http://developer.android.com/training/gestures/scale.html в разделе "Более сложные пример масштабирования":

public boolean onTouchEvent(MotionEvent event) {
    boolean retVal = mScaleGestureDetector.onTouchEvent(event);
    retVal = mGestureDetector.onTouchEvent(event) || retVal;
    return retVal || super.onTouchEvent(event);
}

Конечно, учитывая ошибку, на которую ссылается Ratatat, super.onTouchEvent никогда не будет вызываться в приведенном выше примере, что может быть или не быть хорошо, в зависимости от вашего варианта использования.

person aij    schedule 11.12.2013
comment
Я попробовал это и ответ Рататата, и этот дал мне лучшие результаты. При одновременном панорамировании и масштабировании, если вы используете этот ответ, вы можете просто обрабатывать любое панорамирование в обратном вызове onScroll и любое масштабирование onScale, а не пытаться панорамировать на основе движения в focusX/focusY действия масштабирования. - person Ben Dilts; 08.01.2015
comment
Если вы хотите, чтобы вызывались обе стороны оператора ИЛИ, вы можете использовать | вместо ||. Нравится: return mScaleGestureDetector.onTouchEvent(event) | mGestureDetector.onTouchEvent(event) | super.onTouchEvent(event); - person Robyer; 29.01.2020

Идея ответа Рататата в порядке, но мы все равно должны передавать события в жестДетектор, даже если мы не хотим прокручивать, или будет испорчено.

Я закончил с чем-то вроде этого:

scaleDetector = new ScaleGestureDetector( ... );

gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        if (scaleDetector.isInProgress()) {
            // don't allow scrolling while scaling
            return false;
        }

        // handle scrolling

        return true;
    }
}

И тогда реализация onTouchEvent должна быть такой, как в ответе aij:

boolean result = scaleDetector.onTouchEvent(event);
result = gestureDetector.onTouchEvent(event) || result;
return result || super.onTouchEvent(event);
person yonix    schedule 07.11.2017

Наконец нашел ответ по ссылке: http://code.google.com/p/android/issues/detail?id=42591

@Override
public boolean onTouchEvent(MotionEvent event) {
    boolean result = mScaleGestureDetector.onTouchEvent(event);

    // result is always true here, so I need another way to check for a detected scaling gesture
    boolean isScaling = result = mScaleGestureDetector.isInProgress();
    if (!isScaling) {
        // if no scaling is performed check for other gestures (fling, long tab, etc.)
        result = mCommonGestureDetector.onTouchEvent(event);
    }

    // some irrelevant checks...

    return result ? result : super.onTouchEvent(event);
}
person Ratatat Richie    schedule 02.06.2013