public void OnUpOrCancelMotionEvent(ObservableScrollState scrollState)
 {
     if (_observableScrollViewCallbacks != null)
     {
         _observableScrollViewCallbacks.OnUpOrCancelMotionEvent(scrollState);
     }
 }
        public override bool OnTouchEvent(MotionEvent ev)
        {
            if (_mCallbacks != null)
            {
                switch (ev.ActionMasked)
                {
                case MotionEventActions.Up:
                case MotionEventActions.Cancel:
                    _mIntercepted = false;
                    _mDragging    = false;
                    _mCallbacks.OnUpOrCancelMotionEvent(_mScrollState);
                    break;

                case MotionEventActions.Move:
                    if (_mPrevMoveEvent == null)
                    {
                        _mPrevMoveEvent = ev;
                    }
                    float diffY = ev.GetY() - _mPrevMoveEvent.GetY();
                    _mPrevMoveEvent = MotionEvent.ObtainNoHistory(ev);
                    if (GetCurrentScrollY() - diffY <= 0)
                    {
                        // Can't scroll anymore.

                        if (_mIntercepted)
                        {
                            // Already dispatched ACTION_DOWN event to parents, so stop here.
                            return(false);
                        }

                        // Apps can set the interception target other than the direct parent.
                        ViewGroup parent;
                        if (_mTouchInterceptionViewGroup == null)
                        {
                            parent = (ViewGroup)Parent;
                        }
                        else
                        {
                            parent = _mTouchInterceptionViewGroup;
                        }

                        // Get offset to parents. If the parent is not the direct parent,
                        // we should aggregate offsets from all of the parents.
                        float offsetX = 0;
                        float offsetY = 0;
                        for (View v = this; v != null && v != parent; v = (View)v.Parent)
                        {
                            offsetX += v.Left - v.ScrollX;
                            offsetY += v.Top - v.ScrollY;
                        }

                        MotionEvent eventHistoryLess = MotionEvent.ObtainNoHistory(ev);
                        eventHistoryLess.OffsetLocation(offsetX, offsetY);

                        if (parent.OnInterceptTouchEvent(eventHistoryLess))
                        {
                            _mIntercepted = true;

                            // If the parent wants to intercept ACTION_MOVE events,
                            // we pass ACTION_DOWN event to the parent
                            // as if these touch events just have began now.
                            eventHistoryLess.Action = MotionEventActions.Down;

                            // Return this onTouchEvent() first and set ACTION_DOWN event for parent
                            // to the queue, to keep events sequence.
                            Post(() => parent.DispatchTouchEvent(eventHistoryLess));
                            return(false);
                        }
                        // Even when this can't be scrolled anymore,
                        // simply returning false here may cause subView's click,
                        // so delegate it to super.
                        return(base.OnTouchEvent(ev));
                    }
                    break;
                }
            }
            return(base.OnTouchEvent(ev));
        }