Kotlin users looking for a solution for a normal ScrollView implementation:
As an extension to this answer, I created a custom view that solved my problems very well.
The view (create a new Kotlin file, maintain your package reference on line 1):
import android.annotation.SuppressLint import android.content.Context import android.util.AttributeSet import android.view.MotionEvent import android.widget.ScrollView import kotlin.math.abs class ScrollViewWithEndFunc ( context: Context?, attrs: AttributeSet?, defStyle: Int ) : ScrollView(context, attrs, defStyle) { constructor(context: Context?) : this(context, null, 0) {} constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0) {} interface OnScrollListener { fun onScrollChanged(scrollView: ScrollViewWithEndFunc?, x: Int, y: Int, oldX: Int, oldY: Int) fun onEndScroll(scrollView: ScrollViewWithEndFunc?) } private var isScrolling = false private var isTouching = false private var scrollingRunnable: Runnable? = null private var onScrollListener: OnScrollListener? = null fun setOnScrollListener(onScrollListener: OnScrollListener) { this.onScrollListener = onScrollListener } fun removeOnScrollListener() { this.onScrollListener = null } @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(ev: MotionEvent): Boolean { val action = ev.action if (action == MotionEvent.ACTION_MOVE) { isTouching = true; isScrolling = true } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if (isTouching && !isScrolling) { onScrollListener?.onEndScroll(this) } isTouching = false } return super.onTouchEvent(ev) } override fun onScrollChanged(x: Int, y: Int, oldX: Int, oldY: Int) { super.onScrollChanged(x, y, oldX, oldY) if (abs(oldY - y) > 0) { scrollingRunnable?.let { removeCallbacks(it) } scrollingRunnable = Runnable { if (isScrolling && !isTouching) { onScrollListener?.onEndScroll(this@ScrollViewWithEndFunc) } isScrolling = false scrollingRunnable = null } postDelayed(scrollingRunnable, 200) } onScrollListener?.onScrollChanged(this, x, y, oldX, oldY) } }
XML view implementation:
<your.package.here.ScrollViewWithEndFunc android:id="@+id/scrollview_main_dashboard" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true">
Activity/Fragment implementation:
scrollviewMainDashboard.setOnScrollListener(object : ScrollViewWithEndFunc.OnScrollListener { override fun onScrollChanged(scrollView: ScrollViewWithEndFunc?, x: Int, y: Int, oldX: Int, oldY: Int) { } override fun onEndScroll(scrollView: ScrollViewWithEndFunc?) { /* Scroll ended, handle here */ })
onStartwill do the trick:hsv.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i(TAG,"scroll:"+hsv.getScrollX());}});in onStart() wherehsvis aHorizontalScrollViewworks.