Передача сенсорных событий в родительский вид
У меня есть обычай ViewSwitcher
в котором я реализовал сенсорные события, чтобы я мог прокручивать экраны с помощью сенсорного экрана.
Моя иерархия макетов выглядит следующим образом:
<ViewSwitcher>
<LinearLayout>
<ListView />
</LinearLayout>
<LinearLayout>
<ListView />
</LinearLayout>
</ViewSwitcher>
Теперь проблема в том, что сенсорные события потребляютсяListViews
и я не могу переключить взгляды. Это прекрасно работает, когда у меня нет ListViews
, Мне нужно иметь возможность прокручивать представления и прокручивать ListView
,
Как мне это решить?
РЕДАКТИРОВАТЬ: мне также нужно ListView
элементы для кликабельности.
Заранее спасибо!
9 ответов
Спасибо всем за ответ на вопрос. Но я смог понять это намного проще. Так как мой ViewSwitcher
не обнаружил событие касания, я перехватил событие касания, названное onTouchEvent()
и вернулся false
, Вот:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
onTouchEvent(ev);
return false;
}
Переопределив onInterceptTouchEvent()
Я смог перехватить событие касания в действии. Тогда я позвонил onTouchEvent()
в ViewSwitcher
который обрабатывает переключение ListViews
, И, наконец, вернувшись false
убедитесь, что ViewGroup
не потребляет событие.
Самый простой способ передать TouchEvent дочернего представления в родительское представление - добавить это в дочернее представление:
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
return false;
}
В моем родительском макете единственный способ предотвратить захват события касания дочерним элементом - переопределить onInterceptTouchEvent, чтобы вернуть значение true.
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
return true;
}
Я не думаю, что есть простой способ сделать это.
Это не так сложно, но вам нужно создать собственное представление, расширяющее ListView. Тогда вы можете переопределить onTouch
обработчик и решить (в зависимости от события касания), хотите ли вы обработать его (и вернуть true) или передать его в родительское представление.
Проблема также состоит в том, что, как только представление обрабатывает сенсорное событие, оно получает все остальные...
onTouch () - возвращает логическое значение, указывающее, использует ли ваш слушатель это событие. Важно, что это событие может иметь несколько действий, которые следуют друг за другом. Таким образом, если вы возвращаете false при получении события действия вниз, вы указываете, что вы не использовали событие и также не заинтересованы в последующих действиях из этого события. Таким образом, вас не будут призывать к каким-либо другим действиям внутри события, таким как жест пальцем или событие возможного действия вверх.
Так, например, если вы хотите иметь вертикальное перемещение для прокрутки списка и во время одного и того же события касания (не поднимая палец), вам нужно горизонтальное перемещение для переключения видов, что будет довольно сложно.
Но если вы можете использовать жесты, например, или обрабатывать все в своем собственном представлении и в зависимости от того, что такое MotionEvent, отправьте команды ViewSwitcher.
Необходимо было обрабатывать касание в TextView в родительском представлении с помощью autoLink = "three". Сделали так:
private LinearLayout mParentView;
private TextView mTextView;
private View.OnTouchListener mParentListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
......
return false;
}
};
mParentView.setOnTouchListener(mParentListener);
mTextView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mParentListener.onTouch(mParentView, event);
return false;
}
};
Я установил toucheventlistener на просмотр списка в viewwitcher, обработал событие, обнаружил действие броска и вызвал метод для viewswitcher. оно работает.
Если ваш взгляд хочет передать событие, убедитесь, что вы вернули false в onTouchEvent. В противном случае платформа думает, что вы использовали событие, и дальнейшая обработка не требуется.
Вы пытались установить элементы ListView как не кликабельные, как это: listView.setClickable(false); Это должно распространяться на событие клика вверх.
Вы также можете вставить вызов для обработки touchevent
в dispatchTouchEvent
, но в этом случае вы также должны переопределить onTouchEvent
вернуть true, иначе только первый MotionEvent
ВНИЗ этого жеста будет пройден.
Это осязаемый контейнер-обертка:
<?xml version="1.0" encoding="utf-8"?>
<view xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.example.myapp.FragmentContainer$TouchableWrapper" />
И класс:
public static class TouchableWrapper extends FrameLayout {
private GestureDetector gestureDetector;
public void setGestureDetector(GestureDetector gestureDetector) {
this.gestureDetector = gestureDetector;
}
// these constructors for the XML inflater
public TouchableWrapper(Context context) {
super(context);
}
public TouchableWrapper(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TouchableWrapper(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
Log.d(TAG, "onInterceptTouchEvent " + event.toString());
return false; // true for intercept, false è default and pass on to children View
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d(TAG, "dispatchTouchEvent " + event.toString());
gestureDetector.onTouchEvent(event);
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG, "onTouchEvent " + event.toString());
return true; //return super.onTouchEvent(event);
}
}
Это GestureDetector
ссылка:
private GestureDetector gestureDetector;
Это GestureListener
:
private GestureDetector.SimpleOnGestureListener sOGL = new GestureDetector.SimpleOnGestureListener() {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
goToRight(); // onSwipeRight();
} else {
goToLeft(); // onSwipeLeft();
}
}
result = true;
} else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
// onSwipeBottom();
} else {
// onSwipeTop();
}
}
result = true;
} catch (Exception exception) {
exception.printStackTrace();
}
return result; // return false indicate event not handled
}
};
Ant, чтобы загрузить осязаемый фрагмент контейнера и содержащийся фрагмент:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView()");
View view = inflater.inflate(R.layout.fragmentcontainer, container, false);
gestureDetector = new GestureDetector(view.getContext(), sOGL);
((FragmentContainer.TouchableWrapper) view).setGestureDetector(gestureDetector);
FragmentManager fm = this.getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.pager, frag).commit();
return view;
}