Останавливаем скроллирование 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, после этого список продолжает обрабатывать сообщения о касаниях, но не реагирует на перемещение. Никакого скроллирования не происходит.
    Если же пользователь снова нажал на список, то скроллирование включается обратно.
    Задача решена. При этом код гораздо более предсказуем и корректен.
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 2

      0
      А если его будут кнопками прокручивать?
        0
        Здесь же задача остановить скролл при Drag'n'Drop.

      Only users with full accounts can post comments. Log in, please.