Search code examples
androidandroid-scrollviewontouchlistener

OnTouchListener in View that is inside ScrollView


I have a View that is inside ScrollView. I want to call some method every 80ms as long as the user is holding that View pressed. This is what i have implemented:

final Runnable vibrate = new Runnable() {
    public void run() {
        vibrate();
    }
};

theView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
            final ScheduledFuture<?> vibrateHandle =
                    scheduler.scheduleAtFixedRate(vibrate, 0, 80, MILLISECONDS);
            vibrateHanlers.add(vibrateHandle);
            return true;
        }
        if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL
                || motionEvent.getAction() == MotionEvent.ACTION_UP) {
            clearAllScheduledFutures();
            return false;
        }
        return true;
    }
});

The problem is, ACTION_CANCEL is called for the smallest move of the finger. I know that is because the View is inside ScrollView, but i am not sure what are my options here. Do i create custom ScrollView, and try to find if the desired View is touched and disable the touch event for the ScrollView? Or maybe, disable the touch event for SrollView for small threshold of moving? Or something else?


Solution

  • Here it is how i fixed it.

    I created custom ScrollView:

    public class MainScrollView extends ScrollView {
        private boolean shouldStopInterceptingTouchEvent = false;
    
        public void setShouldStopInterceptingTouchEvent(boolean shouldStopInterceptingTouchEvent) {
            this.shouldStopInterceptingTouchEvent = shouldStopInterceptingTouchEvent;
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            if (shouldStopInterceptingTouchEvent)
                return false;
            else
                return super.onInterceptTouchEvent(ev);
        }
    }
    

    And in the onTouchEvent:

    theView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                svMain.setShouldStopInterceptingTouchEvent(true);
                final ScheduledFuture<?> vibrateHandle =
                        scheduler.scheduleAtFixedRate(vibrate, 0, 80, MILLISECONDS);
                vibrateHanlers.add(vibrateHandle);
                return true;
            }
            if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL
                    || motionEvent.getAction() == MotionEvent.ACTION_UP) {
                svMain.setShouldStopInterceptingTouchEvent(false);
                clearAllScheduledFutures();
                return false;
            }
            return true;
        }
    });
    

    So, instead of determining when to stop intercepting touchEvent in the ScrollView, i am deciding that in the onTouchListener of the View.