Поймать событие, когда палец(ы) проехал над кнопками? onMove

Интерфейс, диалоги, темы, стили, меню
Ответить
vyacheslav
Сообщения: 4
Зарегистрирован: 02 июн 2012, 22:55

Поймать событие, когда палец(ы) проехал над кнопками? onMove

Сообщение vyacheslav » 15 июн 2012, 01:47

Предпололжим есть мною созданый компонент (Form vidget) - модифицированый button.
В его классе я реализовал

Код: Выделить всё

	private OnTouchListener bubbleClick = new OnTouchListener() {
		public boolean onTouch(View v, MotionEvent event) {
			...
			return false;
		}
	};
чтобы ловить, не клик с отпусканием пальца, а соответсвенно Touch. Назовём новый виджет формы и соответствующий класс TouchButton

Предположим, на главной LinearLayout размещены несколько подобных модифицированых TouchButton в виде матрицы 5х5 (кол-во не важно). Если я нажимаю на конкретную TouchButton, то всё срабатывает (в моей реализации она меняет цвет). Но хочу теперь сделать так, чтоб при одном нажатии на одной TouchButton и сдвиге пальца на соседние, срабатывало тоже самое событие. То есть весь вопрос можно перефразировать в том, как отлавливать не onTouch, а что-то вроде onMove события над компонентом?
Т.е. что-то вроде public boolean onMove(View v, MotionEvent event) {... в моей реализации OnTouchListener.

Интересно получится ли что-то подобное при ерзании по экрану несколькими пальцами?

Prospekt
Сообщения: 41
Зарегистрирован: 30 май 2012, 23:06

Re: Поймать событие, когда палец(ы) проехал над кнопками? on

Сообщение Prospekt » 15 июн 2012, 10:35

Как кастыль я бы сделал так:

отлавливал в том же public boolean onTouch(View v, MotionEvent event) отдельно те события у которых (event.getActoin == MotionEvent.ACTION_MOVE) далее брал бы координаты у этого события и последовательно проверял в какую кнопку они попадают. А дальше дело за малым.

vyacheslav
Сообщения: 4
Зарегистрирован: 02 июн 2012, 22:55

Re: Поймать событие, когда палец(ы) проехал над кнопками? on

Сообщение vyacheslav » 17 июн 2012, 00:03

Хм. Дело в том, что как я понял в этом случае надо будет брать координаты относительно всего Layout, а это не очень хорошо. Так же тут прийдёт одному компоненту влиять на другой, а хотелось бы обойтись разработкой внутри одного компонента.

Prospekt
Сообщения: 41
Зарегистрирован: 30 май 2012, 23:06

Re: Поймать событие, когда палец(ы) проехал над кнопками? on

Сообщение Prospekt » 19 июн 2012, 18:27

Не проверено, но сакорее всего так. (опыт показывает)

Если вы нажмете кнопку она станет впуклой. Затем если вы уведете мышку с кнопки, она опять станет нормальной. При этом все остальные компоненты на это не реагируют никак при движениях. Отсюда вывод: все события OnMove получает только тот компонент, на который нажали в самом начале. Поэтому перенапрявлять событие с одной кнопки на другую всеравно придется. Такова GUI архитектура.

Насчет координат, не проверял, но вроде как координаты должны быть относительно самого компонента, а не его лайаута.
Соответственно чтобы вычислить координаты относительно лайоута общего для всех кнопок, нужно к этим координатам прибавить .... ЭЭЭ, оказывается я не знаю, как узнать координаты кнопки относительно лайоута, что ставит под сомнение приминимость моего совета. Странно конечно, но темнемение. Если узнаю - отпишусь.

Аватара пользователя
andev
Сообщения: 219
Зарегистрирован: 13 янв 2012, 17:56

Re: Поймать событие, когда палец(ы) проехал над кнопками? on

Сообщение andev » 20 июн 2012, 04:01

Prospekt писал(а):ЭЭЭ, оказывается я не знаю, как узнать координаты кнопки относительно лайоута, что ставит под сомнение приминимость моего совета. Странно конечно, но темнемение. Если узнаю - отпишусь.
http://stackoverflow.com/questions/3619 ... s-position

и еще где-то видел еще один другой способ. Работоспособность нужно проверять самому в тестовых проектах

AndreyI
Сообщения: 372
Зарегистрирован: 14 май 2012, 16:18

Re: Поймать событие, когда палец(ы) проехал над кнопками? on

Сообщение AndreyI » 20 июн 2012, 05:35

Первым всегда приходит ACTION_DOWN тому View на котором было совершено касание и все дальнейшие event будут приходить только для этого View до момента поднятия пальца с экрана, тогда придут ACTION_UP либо ACTION_CANCEL опять же для этого же View (кстати говоря, приход этих событий, в особенности ACTION_UP, системой не гарантируется). Если у вас установлен listiner на этот View, то вы будете получать эти события в его функцию обратного вызова. Все другие View не будут получать никаких событий до момента отпускания пальца, даже если текущий жест проходит (но не начинается) поверх них.
Определить над каким конкретно View находится палец, имея текущие координаты точки касания (которые можно извлечь из event), очень просто. Вот стандартный прием:

Допустим у нас имеется Layout , который содержит другие View или Layoutы
Извлекаем координаты из event:
int x=(int) event.getRawX();
int y=(int) event.getRawY();

Код: Выделить всё

/**Функция вернет View в который попадают координаты x,y или null за пределами Layout*/
private View ViewFromPoint(int x, int y) {
	Rect frame=new Rect();
	View v;
	for (int i=0;i<Layout.getChildCount();i++){
		v = Layout.getChildAt(i); //Поочередно получаем все View содержащиеся в Layout
		v.getGlobalVisibleRect(frame); //Получаем Rect видимой области каждого View
		if (frame.contains(x, y))return v; // Проверяем попадают ли координаты в прямоугольник
	}
	return null; 
	}
Соответственно, если каждый вложенный в Layout View сам является Layoutoм , в котором есть другие вложенные элементы, то по такому же принципу можно проверить и их и найти конечный View.
На основании вышеизложенного, думаю не сложно написать код, который бы сканировал весь экран начиная от корневого layouta.

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Поймать событие, когда палец(ы) проехал над кнопками? on

Сообщение KamiSempai » 20 июн 2012, 22:13

Решил попробовать сделать такой Layout. Для понятности добавил комментарии. Вот что получилось:

Код: Выделить всё

public class MyLayout extends LinearLayout {
	private View mPressedView; // Будем записывать в этот View нажатый элемент

	public MyLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		// LinearLayout не перехватывает нажатия. Заставим его это делать
		return true;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int[] layoutPosition = new int[2]; // Позиция LinearLayout на экране
		int[] childPosition = new int[2]; // Позиция элемента LinearLayout на экране
		getLocationOnScreen(layoutPosition); // Вычисляем позицию LinearLayout на экране
		Rect childRect = new Rect();
		// Пробегаем все элементы LinearLayout
		for (int i = 0; i < getChildCount(); i++) {
			View child = getChildAt(i);
			child.getFocusedRect(childRect); // Это не занимаемая область child на экране!!! Левая верхняя точка (0,0)
			child.getLocationOnScreen(childPosition);
			// Вычисляем координаты нажатия по child
			float x = event.getX() + layoutPosition[0] - childPosition[0];
			float y = event.getY() + layoutPosition[1] - childPosition[1];
			// Если попали
			if (childRect.contains(Math.round(x), Math.round(y))) {
				// Подгоняем координвты нажатия
				event.setLocation(x, y);
				if (mPressedView != child) {
					// Если нажатие было по другому View
					if (mPressedView != null) { // и до этого было нажато какоето view
						// Сбрасываем нажатие послав событие ACTION_CANCEL
						MotionEvent cancelEvent = MotionEvent.obtain(event);
						cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
						mPressedView.onTouchEvent(cancelEvent);
						// Если этого не сделать View будет оставаться нажатым
					}
					// Меняем событие на ACTION_DOWN
					// Если View не получет это событие оно не будет нажатым
					event.setAction(MotionEvent.ACTION_DOWN);
					mPressedView = child; // Запоминаем нажатый View
				}
				child.onTouchEvent(event); // Вручную вызываем событие нажатия
				return true; // Выходим
			}
		}
		// Если ни один элемент не был нажат, сбрасываем нажатие с текущего View
		if (mPressedView != null) {
			MotionEvent cancelEvent = MotionEvent.obtain(event);
			cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
			mPressedView.onTouchEvent(cancelEvent);
			mPressedView = null;
		}
		return true;
	}
}
На самом деле вариант довольно таки грубый. Если в этот Layout положить обычный LinearLayout, то нажатие на элементы LinearLayout не будет происходить.

PS: Координаты нажатия MotionEvent начинаются относительно левого верхнего угла нажатого элемента. Поэтому если сравниваем или передаем нажатие в другой элемент, нужно это учитывать, что я и сделал.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Ответить