2011-01-13 3 views
10

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

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

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

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

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, чтобы «вернуть false», я не получаю длинные клики. К сожалению, я получаю регулярные клики.

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

ответ

7

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

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

+0

Это похоже на компонент, который я недавно разработал, за исключением того, что я добавил переработку вида на мой и его при поддержке listAdapter. В основном, я ударил кучу кода ListView и привязал его к настраиваемому жесту HorizontalScrollView, как и вы. – jfelectron

+0

Да, я тоже работаю над добавлением этого в SwipeView! Кроме того, я просто (буквально всего около двух минут назад) заметил, что есть ошибка с ListViews в SwipeView. Теперь я исправил ошибку и обновил git repo. https://github.com/fry15/uk.co.jasonfry.android.tools – jsonfry

+3

jfelectron принадлежит вам на GIThub? –

0

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

Я думаю, вам нужно будет обновить эту часть и определить, прокручивались ли вы влево или вправо и возвращались 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); 
} 

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

+0

Вот что происходит. Или ваш пример, что ваш EDIT намерен сделать недействительным? – Andrew

+0

Извините, его ужасный пример, исправляющий еще одну проблему. Попробуем и объясним позже. – Emile

1

Поскольку вы используете 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

Благодарим за отзыв. Я дам ему попробовать. Я должен отметить, что, хотя долгое нажатие - это то, что активируется, и это то, что я заметил, то, что я действительно хотел бы произойти, не имеет утечки жесты, если кто-то промахивается. Есть еще несколько проблем, особенно с телефонами Android, которые могут делать анимацию конца и списка iPhone. Настоящая проблема заключается в том, что swiping отправляет другие жесты в список; и я не знаю, как это остановить. – Andrew

+0

Я только что пробовал это, и это предотвращает длительный щелчок при выполнении, когда я прокручиваю, хотя элемент, из которого сделан ваш палец, выделяет желтый цвет; поэтому какой-то кусочек жеста явно просачивается в список – Andrew

+0

Попробуйте вызвать list.cancelLongPress(), если детектор жестов вернет true ... –

1

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

mGestureDetector.setIsLongpressEnabled(false); 

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

0

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

http://pastie.org/1480091

0

Удалить ваш 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); 
} 
Смежные вопросы