Проблема с обнаружением жестов через ListView - PullRequest
9 голосов
/ 13 января 2011

У меня есть Activity, которая содержит ViewFlipper.ViewFlipper включает в себя 2 макета, оба из которых по сути являются просто ListViews.

Итак, идея в том, что у меня есть два списка, и для перехода от одного к другому я бы использовал горизонтальное перелистывание.* У меня это работает.Тем не менее, независимо от того, какой элемент списка у вас под рукой, когда начинается выполнение, этот элемент также будет долго щелкаться.

Вот соответствующий код, который у меня есть:

public class MyActivity extends Activity implements OnItemClickListener, OnClickListener {

    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;

    private GestureDetector mGestureDetector;
    View.OnTouchListener mGestureListener;

    class MyGestureDetector extends SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            try {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                    return false;
                // right to left swipe
                if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    if (mCurrentScreen != SCREEN_SECONDLIST) {
                        mCurrentScreen = SCREEN_SECONDLIST;
                        mFlipper.setInAnimation(inFromRightAnimation());
                        mFlipper.setOutAnimation(outToLeftAnimation());
                        mFlipper.showNext();
                        updateNavigationBar();
                    }
                }
                else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    if (mCurrentScreen != SCREEN_FIRSTLIST) {
                        mCurrentScreen = SCREEN_FIRSTLIST;
                        mFlipper.setInAnimation(inFromLeftAnimation());
                        mFlipper.setOutAnimation(outToRightAnimation());
                        mFlipper.showPrevious();
                        updateNavigationBar();
                    }
                }
            } catch (Exception e) {
                // nothing
            }
            return true;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mGestureDetector.onTouchEvent(event))
            return true;
        else
            return false;
    }





    ViewFlipper mFlipper;

    private int mCurrentScreen = SCREEN_FIRSTLIST;

    private ListView mList1;
    private ListView mList2;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.layout_flipper);

        mFlipper = (ViewFlipper) findViewById(R.id.flipper);

        mGestureDetector = new GestureDetector(new MyGestureDetector());
        mGestureListener = new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                if (mGestureDetector.onTouchEvent(event)) {
                    return true;
                }
                return false;
            }
        };

        // set up List1 screen

        mList1List = (ListView)findViewById(R.id.list1);
        mList1List.setOnItemClickListener(this);
        mList1List.setOnTouchListener(mGestureListener);

        // set up List2 screen
        mList2List = (ListView)findViewById(R.id.list2);
        mList2List.setOnItemClickListener(this);
        mList2List.setOnTouchListener(mGestureListener);

    }

    …
}

Если яизменить "вернуть истину";Заявление от GestureDetector о «возврате ложных;» я не получаю длинным кликом.К сожалению, я получаю регулярные клики.

Кто-нибудь знает, как я могу обойти это?

Ответы [ 6 ]

7 голосов
/ 19 января 2011

Просто добавить совершенно другой ответ с совершенно другим подходом ...

Я сделал пользовательское представление под названием SwipeView, оно с открытым исходным кодом и т. Д. И т. П., Бла-бла-бла. Это должно позволить вам делать то, что вы хотите сделать так же просто, как и:

mSwipeView.addChild(myList1);
mSwipeView.addChild(myList2);

Вам не придется возиться с детекторами жестов или чем-то еще, и при этом проведите пальцем по вашему пальцу ...

(Это выглядит как ужасная ужасная реклама, извините, пожалуйста. Это был длинный день;)

Есть несколько замечательных ссылок:

http://jasonfry.co.uk/?id=23

http://jasonfry.co.uk/?id=24

http://jasonfry.co.uk/?id=28

1 голос
/ 19 января 2011

Отправьте свой gestDetector и установите

 mGestureDetector.setIsLongpressEnabled(false);

Это предотвратит обнаружение событий длительного нажатия.

1 голос
/ 18 января 2011

Поскольку вы используете GestureDetector, вам нужно реализовать SimpleGestureDetector.onLongPress(MotionEvent e) для обработки длинных кликов.Тем не менее, вы не можете знать элемент списка, который долго нажимался оттуда, поэтому вам нужно запомнить его из обычного onItemLongClick().

class MyGestureDetector extends SimpleOnGestureListener {
    ...
    @Override public void onLongPress(MotionEvent e) {
        if (longClickedItem != -1) {
           Toast.makeText(MainActivity.this, "Long click!", Toast.LENGTH_LONG).show();
        }           
    }
}

int longClickedItem = -1;

@Override
public boolean onItemLongClick(AdapterView<?> list, View view, int position, long id) {
    longClickedItem = position;
    return true;
}

@Override
public boolean onTouchEvent(MotionEvent event) {

    // Reset longclick item if new touch is starting
    if (event.getAction()==MotionEvent.ACTION_DOWN) {
        longClickedItem = -1;
    }

    if (mGestureDetector.onTouchEvent(event))
        return true;
    else
        return false;
}

Я проверил это, и, похоже, он работает нормально.

0 голосов
/ 12 ноября 2014

Убери свой getListView().setOnItemLongClickListener

Добавить в свой класс MyGestureDetector :

public void onLongPress(MotionEvent e) {
    final int position = getListView().pointToPosition((int) e.getX(),
            (int) e.getY());
    // what you want do
    super.onLongPress(e);
}
0 голосов
/ 20 января 2011

Я разработал пользовательский компонент, производный от HorizontalScrollView, который делает это. У меня есть listViews как дочерние представления и проведите без длительного нажатия. Он поддерживается listAdapter, который может быть чем угодно (ArrayAdapter, CursorAdapter ...). Он загружает до трех дочерних представлений, а затем при переворачивании просто меняет их с обеих сторон. Большая часть этого канга из ListView и нуждается в рефакторинге. Слишком долго, чтобы оставлять здесь сообщения напрямую.

http://pastie.org/1480091

0 голосов
/ 14 января 2011

[РЕДАКТИРОВАТЬ] Поцарапайте это, совершенно неправильно.

Я думаю, вам придется обновить эту часть и определить, прокручиваете ли вы влево или вправо, и вернуть true, если вы находитесь в состоянии сканирования.Или, по крайней мере, это то, где я бы посмотрел первым.

 mGestureListener = new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                if (mGestureDetector.onTouchEvent(event)) {
                    return true;
                }
                return false;
            }
        };

Продолжая с моим плохим примером, извините.

В onTouch я считаю, что вы можете протестировать event.getAction () и определить, произошел ли длинный щелчок.Если это так, и вы в движении, тогда верните true, чтобы захватить длинный щелчок.

Боюсь, что это скорее предложение, чем окончательный ответ.

Также вы должны проверить другие [методы], которые вы можете переопределить из SimpleOnGestureListener.Только что проверил, и

@Override
public void onLongPress(MotionEvent e) {
    // TODO Auto-generated method stub
    super.onLongPress(e);
}

может быть чем-то, с чем вы можете поэкспериментировать.

...