Останавливаем скроллирование ScrollView

от автора

Возникла необходимость сделать Drag’n’Drop с элемента ScrollView.
Причем решить эту задачу без использования посторонних библиотек и для всех устройств, начиная с Froyo.
Сам процесс перетаскивания элемента проблемой не является.
Проблема — отключить скроллирование списка после того, как мы уже с ним не работаем.

Дело в том, что после того как мы вытащили элемент за пределы ScrollView и перемещаем его в нужно место, ScrollView продолжает следить за нашими движениями и продолжает скроллироваться. Это не влияет на функционал, но является недопустимым с точки зрения дизайна интерфейса.
Тема достаточно простая. Я думаю, практически каждый программист способен решить эту задачу самостоятельно.
Но проблема в том, что вместо изобретения велосипеда мы часто лезем в интернет в поисках решения.
И находим. В том числе stackoverflow предлагает нам вполне «работающее» решение.
Не удивлюсь, что кто-то может его применить в своем коде без тщательной проверки…
Решение это выглядит вот так:

dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_CANCEL, 0, 0, 0)); 

На первый взгляд — адекватное решение. И оно работает! Вот только оно ломает обработку касаний у ScrollView. Результат — падение приложения с переполнением стэка в непредсказуемый момент времени.
Решение выглядит красивым, но использовать его нельзя!

Есть решение чуть более замудрённое, но гораздо более безопасное и предсказуемое.
Необходимо расширить функционал ScrollView следующим образом:

public class ScrollViewEx extends ScrollView { 	protected boolean scrollActive = true; 	 	public ScrollViewEx(Context context) { 		super(context); 	}	 	public ScrollViewEx(Context context, AttributeSet attrs){ 		super(context,attrs); 	} 	public ScrollViewEx(Context context, AttributeSet attrs, int defStyle){ 		super(context,attrs,defStyle); 	}  	public void stopScroll(){ 		scrollActive = false; 	} 	 	@Override 	public boolean dispatchTouchEvent(MotionEvent event){ 		if (event.getAction()==MotionEvent.ACTION_DOWN) 			scrollActive = true; 		if (scrollActive || event.getAction()!=MotionEvent.ACTION_MOVE) 			return super.dispatchTouchEvent(event); 		return false; 	} } 

Здесь делается очень простая вещь — создаётся переменная, которая отвечает за отключение скролла.
Переменная выставляется программистом в нужный момент и автоматически сбрасывается при нажатии на элемент.
Всё что делает переменная — блокирует виджетом обработку события «перемещение касания».
Соответственно, в нужный момент мы вызываем метод stopScroll, после этого список продолжает обрабатывать сообщения о касаниях, но не реагирует на перемещение. Никакого скроллирования не происходит.
Если же пользователь снова нажал на список, то скроллирование включается обратно.
Задача решена. При этом код на 100% предсказуем и корректен.

ссылка на оригинал статьи http://habrahabr.ru/post/218307/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *