Слушатель жестов во время бездействия

Обновление: см. раздел "Баунти для расширенного вопроса".

У меня есть установка GestureDetector на ListView. ListView - это целый фрагмент, который поступает со стороны окна и частично перекрывает другой фрагмент. Я хочу дать пользователю возможность пронести его близко (т.е. Wunderlist - отличный пример этой функции с правой стороны).

Вот моя настройка:

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

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

            return false;
        }
    };
    listView.setOnTouchListener(gestureListener); 

Сам приемник:

public class GestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_MIN_DISTANCE = 180;
        private static final int SWIPE_THRESHOLD_VELOCITY = 50;

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {

            try {
                if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
                        && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {

                    FragmentManager fma = getActivity()
                            .getSupportFragmentManager();



                    FragmentManager fm = getFragmentManager();
                    FragmentTransaction t = fm.beginTransaction();

                    SherlockListFragment mFrag = new RateReviewFragment();

                    t.add(R.id.main_frag, mFrag);
                    t.setCustomAnimations(R.anim.animation_enter,
                            R.anim.animation_leave);
                    t.remove(mFrag);
                    t.commit();

                }
                return false;
            } catch (Exception e) {

            }
            return false;
        }





        @Override
        public void onLongPress(MotionEvent e) {

            // edited out; this opens up a context menu
        }

    }

Иногда, когда ListView прокручивается вниз (или прокрутка списка прерывается щелчками по строке списка), GestureListener просто останавливается... прослушивает. Прокрутка не будет работать. Вам нужно прокрутить страницу назад, чтобы заставить ее снова работать.

Если кто-то может помочь мне изолировать эти проблемы, я был бы благодарен!

ОБНОВЛЕНИЕ: остается только одна проблема: "слушатель перестает слушать"

ОБНОВЛЕНИЕ ДВА: Возможно, я понял, что это такое; просто не знаю, исправить:

Я нашел что-то после регистрации моих действий; Чем ниже я попадаю в список (и чем больше я взаимодействую с ним), измерения не согласуются. Например, если я перемещаю палец на сантиметр влево и вправо - в самом верху списка, он скажет, что я переместился, например, на 200 пикселей. Но когда у меня возникла проблема, указанная выше, она намного ниже, может быть, 50, для ИМЕЮЩЕГО 1 см расстояния. Поэтому окно не закрывается, потому что оно не соответствует моим условиям if.

Sidenote: я уже неоднократно заявлял, что проблема заключается в том, что "взаимодействует со списком". Это означает: если я быстро прокручу сверху вниз; нет проблем; но если я медленно прокладываю себе путь, возможно, нажав на экран, прокручивая и выключаю, нажимая кнопки на ListView, некоторые из которых открывают новую активность (а затем возвращаются в ту же позицию), это "взаимодействует", с".

Ответ 1

попробуйте это,

    gestureDetector = new GestureDetector(getActivity(),
            new GestureListener());
    View.OnTouchListener gestureListener = new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
           listView.onTouchEvent(event);
           gestureDetector.onTouchEvent(event);

            return true;
        }
    };
    listView.setOnTouchListener(gestureListener);

и произведите следующее изменение

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
  return true;
}

EDIT: Я видел приложение wunderlist, если вы хотите имитировать эту функциональность, попробуйте этот подход,

Использовать onInterceptTouch для корневого макета (из которого listView является дочерним элементом), внутри этого метода вам нужно проверить, что пользователь пропустил или не понравился следующий,

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
  if (ev.getAction() == MotionEvent.ACTION_MOVE) {
    if(/* Check your condition here */) { 
      // User has swiped 
      return true;
    }
  }

  return false; // return false so that the event will be passed to child views.
}

для дополнительной информации Android onInterceptTouchEvent

Ответ 2

измените onTouch следующим образом:

@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
     boolean consumed = gestureDetector.onTouchEvent(event);
     if (event.getAction() == MotionEvent.ACTION_MOVE) {
                return false;
     }

    return consumed;
}

Ответ 3

Не уверен, что это поможет, поскольку бог знает, что происходит за сценой со всеми этими проблемами, но попробуйте следующее:

После того, как был вызван onTouch, перед возвратом ложной проверки, сохраняется ли gestureDetector (не null), (посылка обратного вызова или что-то в класс listview), если нет создайте новый экземпляр и снова вызовите

listView.setOnTouchListener(gestureListener); 

Ответ 4

Первая

Я отмечаю, что в вашем слушателе жестов вы возвращаете true в onDown. Если я правильно понял ваш вопрос, вы оставляете события перехода и вертикального всплытия для ListView, и поэтому вас интересуют только события горизонтального прокрутки в вашем коде.

Почему бы не удалить все функции, которые вам не интересны, оставив все, что вам не интересно, в ListView? Если вы должны иметь их, верните false, что по умолчанию (см. здесь).

В стороне, code для AbsListView (родительский элемент ListView) показывает довольно сложную систему состояний для обработки краны и выступы, поэтому, вероятно, лучше всего оставить как можно меньше, чем возможно, на мой взгляд

Во-вторых

Учитывая ваши последние наблюдения, возможно, ключевым является рассмотрение соотношения между смещением X и Y, а не абсолютным размером салфетки. Хотя я не могу объяснить изменения в размерах салфетки, нас интересует движение, которое преимущественно горизонтально, т.е.

(change in X) >> (change in Y)

Это может быть достигнуто следующим образом:

if ((velocityY == 0.0f) || (Math.abs(velocityX/velocityY) > 3.0f) {
    // The movement is predominantly horizontal
    // Put other checks here (like direction and so on)
    // Then do the stuff
}

Это имеет то преимущество, что вы не используете e1 или e2, что приводит нас к...

В-третьих

Как вы заметили, проблема заключается в том, когда вы взаимодействовали со списком. На данный момент в Event может быть указано несколько указателей. Не гарантируется, что возвращаемая ими информация X и Y по умолчанию относится к какому-либо конкретному событию указателя. Вероятно, стоит проверить, что вы сравниваете информацию из одного и того же события указателя, если вы хотите делать вычисления с использованием X и Y, используя что-то вроде:

int numPointers = e1.getPointerCount();
for (int pointerIndex1 = 0; pointerIndex1 < numPointers; pointerIndex1++) {
    int pointerId = e1.getPointerId(pointerIndex1);
    // find index for pointerId in e2.

    float deltaX = e2.getX(pointerIndex2) - e1.getX(pointerIndex1);
    // and so on
}

Ответ 5

Попробуйте сделать OnTouchListener следующим образом:

View.OnTouchListener gestureListener = new View.OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
    gestureDetector.onTouchEvent(event);
        return true;
    }
};

Затем - вы всегда возвращаете false в onFling(). Верните true в try/catch. И попробуйте передать те же данные методу onScroll в разделе else внутри onFling.