Проблема с обнаружением жестов через ListView
У меня есть активность, которая содержит 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 ответов
Просто добавить совершенно другой ответ с совершенно другим подходом...
Я сделал пользовательское представление под названием SwipeView, оно с открытым исходным кодом и т. Д. И тому подобное. Это должно позволить вам делать то, что вы хотите сделать так же просто, как и:
mSwipeView.addChild(myList1);
mSwipeView.addChild(myList2);
Вам не придется возиться с детекторами жестов или чем-то еще, и, когда вы делаете это, вы должны проводить пальцем...
(Это выглядит как ужасная ужасная реклама, пожалуйста, извините. Это был длинный день;)
Есть несколько замечательных ссылок:
Пойди ты своим жестом детектор и установи
mGestureDetector.setIsLongpressEnabled(false);
Это предотвратит обнаружение длительных событий нажатия.
Так как вы используете 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;
}
Я проверил это, и, кажется, работает нормально.
Удалить свой 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);
}
Я разработал пользовательский компонент, производный от HorizontalScrollView, который делает это. У меня есть listViews как дочерние виды и смахивание без длинных нажатий. Он поддерживается listAdapter, который может быть любым, чем вы хотите (ArrayAdapter, CursorAdapter...). Он загружает до трех дочерних представлений и затем при переворачивании просто меняет их с обеих сторон. Большая часть этого канга из ListView и нуждается в рефакторинге. Слишком долго, чтобы оставлять сообщения прямо здесь.
[Редактировать] Поцарапать это, совершенно неправильно.
Я думаю, что вам придется обновить эту часть и определить, прокручиваете ли вы влево или вправо, и вернуть 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);
}
может быть что-то, что вы могли бы поэкспериментировать.