Android: Как определить, когда свиток закончился


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

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

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

13 64

13 ответов:

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

// 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);
}

вы должны взглянуть на 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

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

SimpleOnGestureListener.onFling() 

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

возвращаясь к этому через несколько месяцев, я теперь следовал другой тактике: используя обработчик (как в примере 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 представления // какие заговоры буферное растровое изображение на экране // сдвинул, чтобы учесть свиток

    [MyView].invalidate();

}

/ / остальная часть класса MyGestureDetector

}

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

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

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

-инициализации "gestureScrolling" логическое "ложь" в конструктор.

- Я установил его в " true "в"onScroll"

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

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

- и часть, которую я сделал, это было по-другому: я также назвал свой метод для обработки "Выполняется" внутри "onFling".

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

public boolean computeScrollOffset() 

наслаждайтесь

harvinder

Я сам этого не делал, но, глядя на onTouch (), вы всегда получаете последовательность 01, поэтому конец должен быть 1 для подъема пальца.

Я не знаю Android, но, глядя на документацию, кажется, что Роб прав: Android ACTION_UP константа попробуйте проверить ACTION_UP от getAction ()?

Edit: что делает e1.getAction() показать? Она когда-нибудь вернется выполняется? В документации говорится, что он удерживает начальное событие down, поэтому, возможно, он также уведомит, когда указатель вверх

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

единственное, что я хотел бы попробовать, это иметь отдельное событие, возможно, onDown, и установить флаг в onScroll, такой как isScrolling. Когда ACTION_UP дается onDown и isScrolling установлен, то вы можете делать все, что хотите, и сбросить isScrolling в false. То есть, предполагая, что onDown вызывается вместе с onScroll, и getAction вернет ACTION_UP во время onDown

Я не пробовал / использовал это, но идея такого подхода:

остановить / прервать перерисовку холста на каждом событии прокрутки подождите 1 С, а затем начните перерисовку холста на каждом свитке.

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

надеюсь, эта идея поможет вам :)

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

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

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

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

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

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

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;
    }

}

Это то, что работал для меня.

я обогатил существующие 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;
    }
}

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

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