Проблемы с обнаружением жесты над ListView с

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

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

У меня это работает. Однако, что когда-либо элемент списка ваш палец на когда салфетки начинает выполнение, этот элемент также будет долго щелкнул.

вот соответствующий код I есть:

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

    }

    …
}

если я изменяю оператор "return true;" из GestureDetector на "return false;", я не получаю длинные клики. К сожалению, я получаю регулярные клики.

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

6 ответов


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

Я сделал пользовательский вид под названием 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


так как вы используете GestureDetector, что нужно сделать, это реализовать SimpleGestureDetector.onLongPress(MotionEvent e) для обработки длинных кликов. Однако вы не можете знать listitem, который был долго нажат оттуда, поэтому вам нужно запомнить его из нормального 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;
}

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


Go вы ваш gestureDetector и установить

 mGestureDetector.setIsLongpressEnabled(false);

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


[EDIT]поцарапайте это, совершенно неправильно.

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

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

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

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

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

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

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

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


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

http://pastie.org/1480091


удалить 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);
}