Android: Как определить, когда свиток закончился
Я использую метод onScroll GestureDetector.SimpleOnGestureListener для прокрутки большого растрового изображения на холсте. Когда прокрутка закончилась, я хочу перерисовать растровое изображение, если пользователь хочет прокрутить дальше ... от края растрового изображения, но я не вижу, как определить, когда прокрутка закончилась (пользователь поднял палец с экрана).
e2.getAction() всегда возвращает значение 2, так что это не поможет. Е2.getPressure кажется, чтобы вернуться достаточно постоянные значения (около 0,25) до финального вызова onScroll, когда давление, кажется, падает примерно до 0,13. Я полагаю, что я мог бы обнаружить это снижение давления, но это будет далеко не надежным.
там должен быть лучший способ: может кто-нибудь помочь, пожалуйста?
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