Android: как определить, когда закончился свиток - PullRequest
65 голосов
/ 19 января 2010

Я использую метод onScroll объекта GestureDetector.SimpleOnGestureListener для прокрутки большого растрового изображения на холсте. Когда прокрутка закончилась, я хочу перерисовать растровое изображение на тот случай, если пользователь захочет прокрутить дальше ... от края растрового изображения, но я не вижу, как определить, когда прокрутка закончилась (пользователь поднял палец с экрана).

e2.getAction () всегда возвращает значение 2, так что это не поможет. Кажется, что e2.getPressure возвращает довольно постоянные значения (около 0,25) до последнего вызова OnScroll, когда давление, кажется, падает примерно до 0,13. Полагаю, я мог бы обнаружить это снижение давления, но это будет далеко не надежно.

Должен быть лучший способ: кто-нибудь может помочь, пожалуйста?

Ответы [ 13 ]

67 голосов
/ 29 сентября 2010

Вот как я решил проблему. Надеюсь, это поможет.

// declare class member variables
private GestureDetector mGestureDetector;
private OnTouchListener mGestureListener;
private boolean mIsScrolling = false;


public void initGestureDetection() {
        // Gesture detection
    mGestureDetector = new GestureDetector(new SimpleOnGestureListener() {
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            handleDoubleTap(e);
            return true;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            handleSingleTap(e);
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            // i'm only scrolling along the X axis
            mIsScrolling = true;                
            handleScroll(Math.round((e2.getX() - e1.getX())));
            return true;
        }

        @Override
        /**
         * Don't know why but we need to intercept this guy and return true so that the other gestures are handled.
         * https://code.google.com/p/android/issues/detail?id=8233
         */
        public boolean onDown(MotionEvent e) {
            Log.d("GestureDetector --> onDown");
            return true;
        }
    });

    mGestureListener = new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {

            if (mGestureDetector.onTouchEvent(event)) {
                return true;
            }

            if(event.getAction() == MotionEvent.ACTION_UP) {
                if(mIsScrolling ) {
                    Log.d("OnTouchListener --> onTouch ACTION_UP");
                    mIsScrolling  = false;
                    handleScrollFinished();
                };
            }

            return false;
        }
    };

    // attach the OnTouchListener to the image view
    mImageView.setOnTouchListener(mGestureListener);
}
4 голосов
/ 06 февраля 2010

Вам следует взглянуть на http://developer.android.com/reference/android/widget/Scroller.html. Особенно это может помочь (отсортировано по значимости):

isFinished();
computeScrollOffset();
getFinalY(); getFinalX(); and getCurrY() getCurrX()
getDuration()

Это означает, что вам нужно создать скроллер.

Если вы хотите использовать прикосновение, вы также можете использовать GestureDetector и определить собственную прокрутку холста.В следующем примере создается ScrollableImageView, и для его использования вы должны определить размеры вашего изображения.Вы можете определить свой собственный диапазон прокрутки, и после завершения прокрутки изображение будет перерисовано.

http://www.anddev.org/viewtopic.php?p=31487#31487

В зависимости от вашего кода вы должны считать недействительным (int l, int t, int r, int b);для признания недействительным.

3 голосов
/ 30 сентября 2010
SimpleOnGestureListener.onFling() 

Кажется, что это происходит, когда заканчивается прокрутка (т. Е. Пользователь отпускает палец), это то, что я использую, и это прекрасно работает для меня.

1 голос
/ 27 апреля 2015

Вот что у меня сработало.

Я обогатил существующий GestureDetector.OnGestureListener с помощью onFingerUp () . Этот слушатель делает все как встроенный GestureDetector и может также прослушивать событие finger up (это не onFling (), так как он вызывается только тогда, когда палец поднят вместе с быстрым движением пальцем).

import android.content.Context;
import android.os.Handler;
import android.view.GestureDetector;
import android.view.MotionEvent;

public class FingerUpGestureDetector extends GestureDetector {
    FingerUpGestureDetector.OnGestureListener fListener;
    public FingerUpGestureDetector(Context context, OnGestureListener listener) {
        super(context, listener);
        fListener = listener;
    }

    public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, OnGestureListener fListener) {
        super(context, listener);
        this.fListener = fListener;
    }

    public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, OnGestureListener fListener) {
        super(context, listener, handler);
        this.fListener = fListener;
    }

    public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, boolean unused, OnGestureListener fListener) {
        super(context, listener, handler, unused);
        this.fListener = fListener;
    }

    public interface OnGestureListener extends GestureDetector.OnGestureListener {
        boolean onFingerUp(MotionEvent e);
    }

    public static class SimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements FingerUpGestureDetector.OnGestureListener {
        @Override
        public boolean onFingerUp(MotionEvent e) {
            return false;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (super.onTouchEvent(ev)) return true;
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            return fListener.onFingerUp(ev);
        }
        return false;
    }
}
1 голос
/ 13 марта 2012

Я уверен, что для вас уже слишком поздно, однако, похоже, я нашел правильное решение для вашего первоначального вопроса и не нуждался в намерении.

Если вы используете Scroller / OverScroller Object для прокрутки, вы должны проверить возвращаемое значение из следующей функции.

public boolean computeScrollOffset() 

наслаждаться

harvinder

1 голос
/ 02 декабря 2010

Я изучал эту же проблему. Я видел Akos Cz ответ на ваш вопрос. Я создал что-то подобное, но с моей версией я заметил, что она работает только для обычной прокрутки - то есть, та, которая не генерирует бросок. Но если сгенерировано смещение - независимо от того, обработал ли я смещение или нет, тогда он НЕ обнаружил «ACTION_UP» в «onTouchEvent». Теперь, может быть, это было что-то с моей реализацией, но если бы это было так, я не мог понять, почему.

После дальнейшего изучения я заметил, что во время сброса «ACTION_UP» каждый раз передавался в «onFling» в «e2». Поэтому я подумал, что именно поэтому он не обрабатывался в «onTouchEvent» в этих случаях.

Чтобы это работало для меня, мне нужно было только вызвать метод для обработки «ACTION_UP» в «onFling», а затем он работал для обоих типов прокрутки. Ниже приведены точные шаги, которые я предпринял для реализации в своем приложении:

- инициализировал логическое значение «gestScrolling» в «false» в конструкторе.

-Я установил значение "true" в "OnScroll"

-создан метод для обработки события "ACTION_UP". Внутри этого события я сбросил «gestSCrolling» в false и затем выполнил остальную часть обработки, которую мне нужно было сделать.

- в «onTouchEvent», если обнаружен «ACTION_UP» и «gestScrolling» = true, тогда я вызвал свой метод для обработки «ACTION_UP»

-И часть, которую я сделал, была другой: я также вызвал свой метод для обработки «ACTION_UP» внутри «onFling».

1 голос
/ 20 августа 2010

Возвращаясь к этому через несколько месяцев, я теперь придерживался другого подхода: с помощью обработчика (как в примере Android Snake) отправлять сообщение приложению каждые 125 миллисекунд, которое запрашивает у него проверку наличия прокрутки. был запущен и прошло ли более 100 миллисекунд с момента последнего события прокрутки.

Кажется, это работает довольно хорошо, но если кто-то может увидеть какие-либо недостатки или возможные улучшения, я был бы рад услышать о них.

Соответствующий код находится в классе MyView:

public class MyView extends android.view.View {

...

private long timeCheckInterval = 125; // milliseconds
private long scrollEndInterval = 100;
public long latestScrollEventTime;
public boolean scrollInProgress = false;

public MyView(Context context) {
    super(context);
}

private timeCheckHandler mTimeCheckHandler = new timeCheckHandler();

class timeCheckHandler extends Handler{

        @Override
        public void handleMessage(Message msg) {
        long now = System.currentTimeMillis();
        if (scrollInProgress && (now>latestScrollEventTime+scrollEndInterval)) {
                    scrollInProgress = false;

// Прокрутка закончена, поэтому введите код здесь

// который вызывает метод doDrawing ()

// для перерисовки растрового изображения, перецентрированного там, где закончилась прокрутка

                    [ layout or view ].invalidate();
        }
        this.sleep(timeCheckInterval);
        }

        public void sleep(long delayMillis) {
            this.removeMessages(0);
            sendMessageDelayed(obtainMessage(0), delayMillis);
            }
    }
}

@Override protected void onDraw(Canvas canvas){
        super.onDraw(canvas);

// код для рисования большого растрового изображения буфера на холсте представления // позиционируется для учета любой выполняемой прокрутки

}

public void doDrawing() {

// код для детального (и трудоемкого) рисования // на большой буферный рисунок

// следующая инструкция сбрасывает часы проверки времени // часы запускаются впервые, когда // основное действие вызывает этот метод при запуске приложения

        mTimeCheckHandler.sleep(timeCheckInterval);
}

// остаток класса MyView

}

и в классе MyGestureDetector

public class MyGestureDetector extends SimpleOnGestureListener {

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
        float distanceY) {

    [MyView].scrollInProgress = true;
        long now = System.currentTimeMillis();  
    [MyView].latestScrollEventTime =now;

    [MyView].scrollX += (int) distanceX;
    [MyView].scrollY += (int) distanceY;

// следующая инструкция вызывает метод onDraw View // который выводит растровое изображение буфера на экран // сдвинуто с учетом прокрутки

    [MyView].invalidate();

}

// остаток класса MyGestureDetector

}

0 голосов
/ 09 августа 2018

Моя попытка добавить дополнительную функциональность в детектор жестов. Надеюсь, это поможет кому-то лучше использовать свое время ...

https://gist.github.com/WildOrangutan/043807ddbd68978179b7cea3b53c71e8

0 голосов
/ 22 марта 2013

Я думаю, что это будет работать, как вам нужно

protected class SnappingGestureDetectorListener extends SimpleOnGestureListener{

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){
        boolean result = super.onScroll(e1, e2, distanceX, distanceY);

        if(!result){
            //Do what you need to do when the scrolling stop here
        }

        return result;
    }

}
0 голосов
/ 10 февраля 2010

Извлечение из события onScroll из API GestureListener: текст ссылки

публичный абстрактный логический onScroll (MotionEvent e1, MotionEvent e2, плавать distanceX, float distanceY) С: API Уровень 1

Возвращает * true, если событие используется, иначе false

Возможно, после того, как событие было израсходовано, действие завершено, и пользователь убрал палец с экрана или, по крайней мере, завершил действие onScroll

Затем вы можете использовать это в операторе IF для поиска == true и затем приступить к следующему действию.

...