3

I was trying to hide a button during scroll view is in idle state.the button should be invisible only during scrolling time.(Rest of the time button should be visible)

scrollView.setOnScrollChangeListener(new ScrollView.OnScrollChangeListener() {
    @Override
    public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
        if (scrollX == scrollY)  {
            Button.setVisibility(View.VISIBLE);
        } else if ((scrollY > oldScrollY)) {
            Button.setVisibility(View.INVISIBLE);
        }
    }
});
Libin
  • 43
  • 1
  • 5
  • this may help you https://stackoverflow.com/questions/8181828/android-detect-when-scrollview-stops-scrolling – AskNilesh Oct 30 '17 at 05:34
  • Possible duplicate of [Android: Detect when ScrollView stops scrolling](https://stackoverflow.com/questions/8181828/android-detect-when-scrollview-stops-scrolling) – Abdul Waheed Oct 30 '17 at 05:37
  • This will help you for sure: [Android Detect Scrolling issue](https://edu.masoomyf.com/2022/09/blog-post.html) – masoomyf Sep 10 '22 at 14:10

4 Answers4

5

Find the solution

    scrollView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch( View v, MotionEvent event ) {
            switch ( event.getAction( ) ) {
                case MotionEvent.ACTION_SCROLL:
                case MotionEvent.ACTION_MOVE:
                    Log.e( "SCROLL", "ACTION_SCROLL" );
                    break;
                case MotionEvent.ACTION_DOWN:
                    Log.e( "SCROLL", "ACTION_DOWN" );
                    break;
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP:
                    Log.e( "SCROLL", "SCROLL_STOP" );
                    break;
            }
            return false;
        }
    });
2

Even though this question is a little old and ScrollView are not as used, I had to implement something related to this, I'm using a NestedScrollView per recommendation and Kotlin.

If you are using Java this won't be possible or as 'clean', you would need to create static util methods instead, with Kotlin you can do extension functions as shown. If you are using a ScrollView just change what you see here from NestedScrollView to ScrollView.

I'll show two ways to implement this:

First, create your NestedScrollViewExtensions.kt file:

1.

If you want a simplified (my preferred) version just add this snippet to your NestedScrollViewExtensions.kt file:


fun NestedScrollView.onScrollStateChanged(startDelay: Long = 100, stopDelay: Long = 400, listener: (Boolean) -> Unit) {
    setOnTouchListener { _, event ->
        when (event.action) {
            MotionEvent.ACTION_SCROLL, MotionEvent.ACTION_MOVE -> {
                handler.postDelayed({
                    listener.invoke(true)
                }, startDelay)
            }

            MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
                handler.postDelayed({
                    listener.invoke(false)
                }, stopDelay)
            }
        }
        false // Do not consume events
    }
}

This way the implementation is cleaner:


        scroll_view.onScrollStateChanged { isScrolling -> 
            if(isScrolling) fab.shrink() else fab.extend()
        }

2

And the not so clean way


interface NestedViewScrollChangedListener {
    fun onScrollStart()

    fun onScrollStop()
}

@SuppressLint("ClickableViewAccessibility")
fun NestedScrollView.onScrollStateChanged(listener: NestedViewScrollChangedListener) {
    this.setOnTouchListener { _, event ->
        when(event.action) {
            MotionEvent.ACTION_SCROLL, MotionEvent.ACTION_MOVE -> {
                handler.postDelayed({
                    listener.onScrollStart()
                }, 100)
            }

            MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
                handler.postDelayed({
                    listener.onScrollStop()
                }, 400)
            }
        }
        false // Don't consume touch events
    }
}

In here I'm using a simple delay that works for me as I need to have an animation happen, feel free to remove all the handler.postDelay() and call the listener directly.

The interface above NestedViewScrollChangedListener needs to be implemented like this:


scroll_view.onScrollStateChanged(object : NestedViewScrollChangedListener {
            override fun onScrollStart() {
                fab.shrink()
            }

            override fun onScrollStop() {
                fab.extend()
            }
        })

Good luck :)

Joaquim Ley
  • 4,038
  • 2
  • 24
  • 42
  • add view.performClick() above false to solve warning of "onTouch lambda should call View#performClick when a click is detected" – Mia May 30 '23 at 03:52
1

in kotlin you can use this

inline fun NestedScrollView.scrollState(crossinline idle: () -> Unit, crossinline scrolled: () -> Unit) {
    setOnTouchListener { _, event ->
        when (event.action) {
            MotionEvent.ACTION_SCROLL,
            MotionEvent.ACTION_MOVE,
            MotionEvent.ACTION_DOWN -> {
                scrolled()
            }
            MotionEvent.ACTION_CANCEL,
            MotionEvent.ACTION_UP -> {
                idle()
            }
        }
        false
    }
}
raditya gumay
  • 2,951
  • 3
  • 17
  • 24
0

try below code

@Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if(scrollState == SCROLL_STATE_IDLE){
            //do your stuff here
        }
}
Munir
  • 2,548
  • 1
  • 11
  • 20