Scrollview не смахивает, когда он слишком короткий, чтобы прокрутить - PullRequest
8 голосов
/ 24 августа 2010

Я довольно новичок в разработке приложений для Android, и я играл с жестами смахивания, используя Android SimpleOnGestureListener и ViewFlipper. Есть 3 дочерних элемента ViewFlipper, и каждый является ScrollView. Все они динамически заполняются при загрузке Activity, и после этого они не меняются. ScrollView - это место, где прикреплены SimpleOnGestureListeners.

Вот макет, который я использую:
+ ViewFlipper
++ ScrollView (x3, по одному на каждую страницу, каждая со следующим:)
+++ LinearLayout (вертикальный)
++++ TextView
++++ TableLayout (динамически заполненный с TableRows)
++++ Вид

Я расширил метод onFling общим учебным кодом, который вы можете найти в любом месте онлайн, и он прекрасно работает - за исключением случаев, когда один из ScrollViews не содержит достаточно контента для прокрутки.

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

Когда я пролистываю прокручиваемую страницу, я получаю что-то полное «inClick», «onScroll», «onFling» и т. Д. На слишком короткой странице для прокрутки я получаю «inClick», «onShowPress» «в onLongPress», и это только в том случае, если я касаюсь содержимого внутри дочерних элементов слишком короткого прокрутки - если я касаюсь в другом месте, я вообще не получаю никаких событий.

Идеи о том, что не так или как обнаружить жест смахивания, независимо от размера ScrollView?

РЕДАКТИРОВАТЬ: я определил, что когда я запускаю это на эмуляторе Android 2.2, в отличие от эмулятора Android 2.1u1 DroidX, который я использовал, он исчезает. Это воспроизводимо в нескольких средах.


У меня есть кое-что еще об этом; кажется, что onInterceptTouchEvent не вызывается для каждого события движения, когда представление прокрутки содержится в флиппере (или в WorkspaceView).

В частности, поведение, которое я обнаружил при изменении другого класса представления для исправления этой же самой проблемы (она не уникальна для флипперов), было следующим: обратите внимание, что это только Android 2.1:

Если представление прокрутки достаточно длинное для прокрутки, событие движения ACTION_DOWN перехватывается представлением ScrollView, и каждое последующее событие ACTION_MOVE проходит через onInterceptTouchEvent флиппера, где оно перехватывается и обрабатывается соответствующим образом. В Android 2.2 это происходит независимо от длины прокрутки.

Назад к 2.1: Если представление прокрутки недостаточно длинное для прокрутки, событие движения ACTION_DOWN не перехватывается просмотром прокрутки, но вместо этого возвращается к onTouchEvent флиппера. Все последующие события ACTION_MOVE того же жеста пропускают функцию onInterceptTouchEvent и переходят прямо к функции onTouchEvent!

Способ, которым я решил это, заключался в том, чтобы взять функциональность, имеющуюся в onTouchEvent, для событий ACTION_MOVE и преобразовать ее в свой собственный метод. Таким образом, у меня может быть вызов onTouchEvent onInterceptTouchEvent, за которым следует эта функциональность, если он обнаруживает, что событие ранее прошло необработанным.

case MotionEvent.ACTION_MOVE:

                if (touchState == TOUCH_STATE_SCROLLING) {
                    handleScrollMove(ev);
                } else {
    //              Log.d("workspace","caught a move touch event but not scrolling");
                    //NOTE:  We will never hit this case in Android 2.2.  This is to fix a 2.1 bug.
                    //We need to do the work of interceptTouchEvent here because we don't intercept the move
                    //on children who don't scroll.

                    Log.d("workspace","handling move from onTouch");

                    if(onInterceptTouchEvent(ev) && touchState == TOUCH_STATE_SCROLLING){
                        handleScrollMove(ev);
                    }

                }

                break;

Это из WorkspaceView.java (модификация Android Workspace.java, найденная в проекте andro-views в коде Google, и теперь здесь: Горизонтальная прокрутка "tab" между представлениями ). В случае, когда мы получаем событие перемещения и прокручиваем (что происходит, только если мы сознательно решили перехватить его - т. Е. Оно установлено в функции перехвата, поэтому мы уже были в функции перехвата), мы выполняем поведение движения мы желаем. Если мы получаем событие перемещения здесь, и мы не прокручиваем, то мы отправляем событие обратно через onIntercept, а затем проверяем, настроена ли сейчас прокрутка. Если это так, мы выполняем действие.

Это не элегантно, но работает!

Ответы [ 2 ]

7 голосов
/ 10 сентября 2010

Мне нужно было создать новый класс, который расширил ScrollView, и использовал это:

@Override
public boolean onTouchEvent(MotionEvent event) {
    super.onTouchEvent(event);
    return gestureDetector.onTouchEvent(event);
}

@Override 
public boolean dispatchTouchEvent(MotionEvent ev){
    gestureDetector.onTouchEvent(ev);
    super.dispatchTouchEvent(ev); 
    return true;
} 

Я понятия не имею, почему, но если я попытаюсь вернуть что-либо, кроме true, в dispatchTouchEvent (логическая вещь будет иметьбыл до

return (gestureDetector.onTouchEvent(ev) || super.dispatchTouchEvent(ev)); 

, если я правильно понимаю), это не работает, и это работает.

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

Попробуйте установить android:fillViewport="true" в макете XML для каждого из ScrollView с. Это говорит о том, что ScrollView должно быть таким же большим, как представление, в котором оно содержится.

...