public override bool OnTouchEvent(MotionEvent ev) { if (_velocityTracker == null) { _velocityTracker = VelocityTracker.Obtain(); } _velocityTracker.AddMovement(ev); var action = ev.Action; var x = ev.GetX(); switch (action) { case MotionEventActions.Down: /* * If being flinged and user touches, stop the fling. isFinished will be false if being flinged. */ if (!_scroller.IsFinished) { _scroller.AbortAnimation(); } // Remember where the motion event started _lastMotionX = x; _touchState = _scroller.IsFinished ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING; break; case MotionEventActions.Move: var xDiff = (int)Math.Abs(x - _lastMotionX); var xMoved = xDiff > _touchSlop; if (xMoved) { // Scroll if the user moved far enough along the X axis _touchState = TOUCH_STATE_SCROLLING; } if (_touchState == TOUCH_STATE_SCROLLING) { // Scroll to follow the motion event var deltaX = (int)(_lastMotionX - x); _lastMotionX = x; var scrollX = ScrollX; if (deltaX < 0) { if (scrollX > 0) { ScrollBy(Math.Max(-scrollX, deltaX), 0); } } else if (deltaX > 0) { var availableToScroll = GetChildAt(ChildCount - 1).Right - scrollX - Width; if (availableToScroll > 0) { ScrollBy(Math.Min(availableToScroll, deltaX), 0); } } } break; case MotionEventActions.Up: if (_touchState == TOUCH_STATE_SCROLLING) { var velocityTracker = _velocityTracker; velocityTracker.ComputeCurrentVelocity(1000, _maximumVelocity); var velocityX = (int)velocityTracker.XVelocity; if (velocityX > SNAP_VELOCITY && _currentScreen > 0) { // Fling hard enough to move left SnapToScreen(_currentScreen - 1); } else if (velocityX < -SNAP_VELOCITY && _currentScreen < ChildCount - 1) { // Fling hard enough to move right SnapToScreen(_currentScreen + 1); } else { SnapToDestination(); } if (_velocityTracker != null) { _velocityTracker.Recycle(); _velocityTracker = null; } } _touchState = TOUCH_STATE_REST; break; case MotionEventActions.Cancel: _touchState = TOUCH_STATE_REST; break; } return(true); }
public override bool DispatchTouchEvent(MotionEvent e) { var index = e.ActionIndex; var action = e.ActionMasked; var pointerId = e.GetPointerId(index); switch (action & MotionEventActions.Mask) { case MotionEventActions.PointerDown: MultiTouchGesture?.Invoke(this, EventArgs.Empty); break; case MotionEventActions.Up: if ((DateTime.Now - _downTime).TotalMilliseconds < 200) { SingleTapGesture?.Invoke(this, EventArgs.Empty); } break; } switch (action) { case MotionEventActions.Down: _downTime = DateTime.Now; if (_velocityTracker == null) { _velocityTracker = VelocityTracker.Obtain(); } else { // Reset the velocity tracker back to its initial state. _velocityTracker.Clear(); } if (IfVelocityTrackerIsNull()) { return(true); } _velocityTracker.AddMovement(e); break; case MotionEventActions.Move: if (IfVelocityTrackerIsNull()) { return(true); } _velocityTracker.AddMovement(e); _velocityTracker.ComputeCurrentVelocity(Sensitivity); TryExportVelocity(_velocityTracker.GetXVelocity(pointerId), _velocityTracker.GetYVelocity(pointerId)); break; case MotionEventActions.Up: case MotionEventActions.Cancel: if (IfVelocityTrackerIsNull()) { return(true); } _velocityTracker.Recycle(); _velocityTracker = null; break; } return(true); }
public override bool OnInterceptTouchEvent( CoordinatorLayout parent, Java.Lang.Object childObject, MotionEvent @event) { View child = Android.Runtime.Extensions.JavaCast <View>(childObject); if (!child.IsShown) { Debug.WriteLineIf(DebugTrace, $"OnInterceptTouchEvent: return false"); return(false); } int action = MotionEventCompat.GetActionMasked(@event); // Record the velocity if (action == (int)MotionEventActions.Down) { reset(); } if (mVelocityTracker == null || mVelocityTracker.Handle == IntPtr.Zero) { mVelocityTracker = VelocityTracker.Obtain(); } mVelocityTracker.AddMovement(@event); switch (action) { case (int)MotionEventActions.Up: case (int)MotionEventActions.Cancel: mTouchingScrollingChild = false; mActivePointerId = MotionEvent.InvalidPointerId; // Reset the ignore flag if (mIgnoreEvents) { mIgnoreEvents = false; return(false); } break; case (int)MotionEventActions.Down: int initialX = (int)@event.GetX(); mInitialY = (int)@event.GetY(); View nestedScroll; if (mNestedScrollingChildRef.TryGetTarget(out nestedScroll) && parent.IsPointInChildBounds(nestedScroll, initialX, mInitialY)) { mActivePointerId = @event.GetPointerId(@event.ActionIndex); //mTouchingScrollingChild = true; } mIgnoreEvents = mActivePointerId == MotionEvent.InvalidPointerId && !parent.IsPointInChildBounds(child, initialX, mInitialY); break; } if (!mIgnoreEvents && mViewDragHelper.ShouldInterceptTouchEvent(@event)) { Debug.WriteLineIf(DebugTrace, $"OnInterceptTouchEvent: return true"); return(true); } // We have to handle cases that the ViewDragHelper does not capture the bottom sheet because // it is not the top most view of its parent. This is not necessary when the touch event is // happening over the scrolling content as nested scrolling logic handles that case. View scroll; var result = action == (int)MotionEventActions.Move && mNestedScrollingChildRef.TryGetTarget(out scroll) && !mIgnoreEvents && mState != STATE_DRAGGING && !parent.IsPointInChildBounds(scroll, (int)@event.GetX(), (int)@event.GetY()) && Math.Abs(mInitialY - @event.GetY()) > mViewDragHelper.TouchSlop; Debug.WriteLineIf(DebugTrace, $"OnInterceptTouchEvent: return {result}"); return(result); }
public override bool OnTouchEvent(MotionEvent ev) { if (_mVelocityTracker == null) { _mVelocityTracker = VelocityTracker.Obtain(); } _mVelocityTracker.AddMovement(ev); MotionEventActions action = ev.Action; float x = ev.GetX(); switch (action) { case MotionEventActions.Down: /* * If being flinged and user touches, stop the fling. isFinished will be false if * being flinged. */ if (!_mScroller.IsFinished) { _mScroller.AbortAnimation(); } // Remember where the motion event started _mLastMotionX = x; _mTouchState = _mScroller.IsFinished ? TOUCH_STATE_REST : TOUCH_STATE_HORIZONTAL_SCROLLING; break; case MotionEventActions.Move: var xDiff = (int)Math.Abs(x - _mLastMotionX); bool xMoved = xDiff > _mTouchSlop; if (xMoved) { // Scroll if the user moved far enough along the X axis _mTouchState = TOUCH_STATE_HORIZONTAL_SCROLLING; } if (_mTouchState == TOUCH_STATE_HORIZONTAL_SCROLLING) { // Scroll to follow the motion event var deltaX = (int)(_mLastMotionX - x); _mLastMotionX = x; int scrollX = ScrollX; if (deltaX < 0) { if (scrollX > 0) { ScrollBy(Math.Max(-scrollX, deltaX), 0); } } else if (deltaX > 0) { int availableToScroll = GetChildAt(ChildCount - 1).Right - scrollX - Width; if (availableToScroll > 0) { ScrollBy(Math.Min(availableToScroll, deltaX), 0); } } } break; case MotionEventActions.Up: if (_mTouchState == TOUCH_STATE_HORIZONTAL_SCROLLING) { VelocityTracker velocityTracker = _mVelocityTracker; velocityTracker.ComputeCurrentVelocity(VELOCITY_UNIT_PIXELS_PER_SECOND, _mMaximumVelocity); var velocityX = (int)velocityTracker.XVelocity; if (velocityX > mDensityAdjustedSnapVelocity && _mCurrentScreen > 0) { // Fling hard enough to move left SnapToScreen(_mCurrentScreen - 1); } else if (velocityX < -mDensityAdjustedSnapVelocity && _mCurrentScreen < ChildCount - 1) { // Fling hard enough to move right SnapToScreen(_mCurrentScreen + 1); } else { SnapToDestination(); } if (_mVelocityTracker != null) { _mVelocityTracker.Recycle(); _mVelocityTracker = null; } } _mTouchState = TOUCH_STATE_REST; break; case MotionEventActions.Cancel: _mTouchState = TOUCH_STATE_REST; break; } return(true); }
public override bool OnInterceptTouchEvent(MotionEvent ev) { if (!_enabled) { return(false); } var action = (int)ev.Action & MotionEventCompat.ActionMask; #if DEBUG if (action == (int)MotionEventActions.Down) { Log.Verbose(Tag, "Recieved ACTION_DOWN"); } #endif if (action == (int)MotionEventActions.Cancel || action == (int)MotionEventActions.Up || (action != (int)MotionEventActions.Down && _isUnableToDrag)) { EndDrag(); return(false); } switch (action) { case (int)MotionEventActions.Move: DetermineDrag(ev); break; case (int)MotionEventActions.Down: var index = MotionEventCompat.GetActionIndex(ev); ActivePointerId = MotionEventCompat.GetPointerId(ev, index); if (ActivePointerId == InvalidPointer) { break; } _lastMotionX = _initialMotionX = MotionEventCompat.GetX(ev, index); _lastMotionY = MotionEventCompat.GetY(ev, index); if (ThisTouchAllowed(ev)) { _isBeingDragged = false; _isUnableToDrag = false; if (IsMenuOpen && _viewBehind.MenuTouchInQuickReturn(_content, _curItem, ev.GetX() + _scrollX)) { _quickReturn = true; } } else { _isUnableToDrag = true; } break; case (int)MotionEventActions.PointerUp: OnSecondaryPointerUp(ev); break; } if (!_isBeingDragged) { if (VelocityTracker == null) { VelocityTracker = VelocityTracker.Obtain(); } VelocityTracker.AddMovement(ev); } return(_isBeingDragged || _quickReturn); }
public override bool OnTouchEvent(MotionEvent e) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.Obtain(); } mVelocityTracker.AddMovement(e); MotionEventActions action = e.Action; float x = e.GetX(); switch (action) { case MotionEventActions.Down: if (!mScroller.IsFinished) { mScroller.AbortAnimation(); } mLastMotionX = x; if (mScroller.IsFinished) { mTouchState = TOUCH_STATE_REST; } else { mTouchState = TOUCH_STATE_HORIZONTAL_SCROLLING; } break; case MotionEventActions.Move: int xDiff = (int)Math.Abs(x - mLastMotionX); bool xMoved = xDiff > mTouchSlop; if (xMoved) { mTouchState = TOUCH_STATE_HORIZONTAL_SCROLLING; } if (mTouchState == TOUCH_STATE_HORIZONTAL_SCROLLING) { int deltaX = (int)(mLastMotionX - x); mLastMotionX = x; int scrollX = this.ScrollX; if (deltaX < 0) { if (scrollX > 0) { ScrollBy(Math.Max(-scrollX, deltaX), 0); } } else if (deltaX > 0) { if (this.ChildCount >= 1) { int avalableToScroll = this.GetChildAt(this.ChildCount - 1).Right - scrollX - Width; if (avalableToScroll > 0) { ScrollBy(Math.Min(avalableToScroll, deltaX), 0); } } } } break; case MotionEventActions.Up: if (mTouchState == TOUCH_STATE_HORIZONTAL_SCROLLING) { VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.ComputeCurrentVelocity(VELOCITY_UNIT_PIXELS_PER_SECOND, mMaximumVelocity); int velocityX = (int)velocityTracker.XVelocity; if (velocityX > mDensityAdjustedSnapVelocity && mCurrentScreen > 0) { SnapToScreen(mCurrentScreen - 1); } else if (velocityX < -mDensityAdjustedSnapVelocity && mCurrentScreen < this.ChildCount - 1) { SnapToScreen(mCurrentScreen + 1); } else { SnapToDestination(); } if (mVelocityTracker != null) { mVelocityTracker.Recycle(); mVelocityTracker = null; } mTouchState = TOUCH_STATE_REST; } break; case MotionEventActions.Cancel: mTouchState = TOUCH_STATE_REST; break; default: break; } return(true); }
public override bool OnTouchEvent(MotionEvent ev) { if (ev.Action == MotionEventActions.Down && ev.EdgeFlags != 0) { // Don't handle edge touches immediately -- they may actually belong to one of our // descendants. return(false); } if (!CanScroll) { return(false); } if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.Obtain(); } mVelocityTracker.AddMovement(ev); MotionEventActions action = ev.Action; float y = ev.GetY(); float x = ev.GetX(); switch (action) { case MotionEventActions.Down: /* * If being flinged and user touches, stop the fling. isFinished * will be false if being flinged. */ if (!mScroller.IsFinished) { mScroller.AbortAnimation(); } // Remember where the motion event started mLastMotionY = y; mLastMotionX = x; break; case MotionEventActions.Move: // Scroll to follow the motion event int deltaX = (int)(mLastMotionX - x); int deltaY = (int)(mLastMotionY - y); mLastMotionX = x; mLastMotionY = y; if (deltaX < 0) { if (ScrollX < 0) { deltaX = 0; } } else if (deltaX > 0) { int rightEdge = Width - PaddingRight; int availableToScroll = GetChildAt(0).Right - ScrollX - rightEdge; if (availableToScroll > 0) { deltaX = System.Math.Min(availableToScroll, deltaX); } else { deltaX = 0; } } if (deltaY < 0) { if (ScrollY < 0) { deltaY = 0; } } else if (deltaY > 0) { int bottomEdge = Height - PaddingBottom; int availableToScroll = GetChildAt(0).Bottom - ScrollY - bottomEdge; if (availableToScroll > 0) { deltaY = System.Math.Min(availableToScroll, deltaY); } else { deltaY = 0; } } if (deltaY != 0 || deltaX != 0) { ScrollBy(deltaX, deltaY); } break; case MotionEventActions.Up: VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.ComputeCurrentVelocity(1000, mMaximumVelocity); int initialXVelocity = (int)velocityTracker.XVelocity; int initialYVelocity = (int)velocityTracker.YVelocity; if ((System.Math.Abs(initialXVelocity) + System.Math.Abs(initialYVelocity) > mMinimumVelocity) && ChildCount > 0) { Fling(-initialXVelocity, -initialYVelocity); } if (mVelocityTracker != null) { mVelocityTracker.Recycle(); mVelocityTracker = null; } break; } return(true); }
public ScrollHelper(GestureHelper gestureHelper) { this.GestureHelper = gestureHelper; this.VelocityTracker = VelocityTracker.Obtain(); }
/// <summary> /// Called when a touch event has been passed to the list view for processing. /// Process according to the event type /// </summary> /// <param name="touchedView">The view given the event - not used assumed to be owner ShoppingListView</param> /// <param name="touchEvent">THe touch event</param> /// <returns>True if the event has been consumed and should not be further processed</returns> public bool OnTouch(View touchedView, MotionEvent touchEvent) { // Assume the event is not consumed bool touchConsumed = false; switch (touchEvent.Action) { case MotionEventActions.Down: { // Adjust touch position to be relative to the parent view int[] viewCoords = new int[2]; monitoredView.GetLocationOnScreen(viewCoords); int relX = ( int )touchEvent.RawX - viewCoords[0]; int relY = ( int )touchEvent.RawY - viewCoords[1]; // Work out if a child of the parent view has been selected // This is a bit of a brute force way of doing this but can cope with different height items. int childIndex = 0; bool childFound = false; Rect hitRect = new Rect(); while ((childIndex < monitoredView.ChildCount) && (childFound == false)) { View child = monitoredView.GetChildAt(childIndex); child.GetHitRect(hitRect); // Check if this child has been selected - all coordinates relative to the parent if (hitRect.Contains(relX, relY) == true) { childFound = true; // Save the view selectedView = child; selectedPosition = monitoredView.GetPositionForView(child); // Check if this child can be selected if (ItemSelectionHandler != null) { SelectionEventArgs args = new SelectionEventArgs { Position = selectedPosition, ViewSelected = child }; ItemSelectionHandler.Invoke(this, args); if (args.Cancel == true) { selectedView = null; } } } else { childIndex++; } } // If a child hasn't been selected check whether or not group swipes are allowed if (childFound == false) { selectedPosition = -1; // If group swiping is allowed (in either direction) then specify the parent view as the selected view if ((RightGroupSwipe == true) || (LeftGroupSwipe == true)) { selectedView = monitoredView; } } // If a view has been selected then set up a velocity tracker and record the initial x coordinate if (selectedView != null) { velocity = VelocityTracker.Obtain(); velocity.AddMovement(touchEvent); // Record the raw starting X position to determine how far to translate the view in response to user // moves initialDownX = touchEvent.RawX; touchConsumed = true; } break; } case MotionEventActions.Move: { // If a view has been selected then determine how far it has been moved if (selectedView != null) { // Add the current movement to those held by the tracker velocity.AddMovement(touchEvent); float deltaX = touchEvent.RawX - initialDownX; if (swiping == false) { // Not already swiping. Check if the movement is deliberate and is more horizontal than vertical // Get the velocity in pixels / sec // Check if swiping is actually allowed if (SwipingAllowed(deltaX) == true) { velocity.ComputeCurrentVelocity(1000); if ((Math.Abs(deltaX) > wander) && (Math.Abs(velocity.XVelocity) > Math.Abs(velocity.YVelocity))) { swiping = true; } } } if (swiping == true) { // Move the view unless swiping is not allowed if (SwipingAllowed(deltaX) == true) { // Move the selected view // If this is a group swipe then move the parent view instead if (((deltaX > 0) && (RightGroupSwipe == true)) || ((deltaX < 0) && (LeftGroupSwipe == true))) { monitoredView.TranslationX = deltaX; // If moving left and there is a right reveal view then move it as well if ((deltaX < 0) && (RightRevealView != null)) { RightRevealView.TranslationX = monitoredView.Width + deltaX; RightRevealView.Visibility = ViewStates.Visible; } // If moving right and there is a left reveal view then move it as well if ((deltaX > 0) && (LeftRevealView != null)) { LeftRevealView.TranslationX = deltaX - monitoredView.Width; LeftRevealView.Visibility = ViewStates.Visible; } // If we've been moving an individual child then make sure it is put back where // we found it. Don't so this if the selected child is the parent if ((selectedView != monitoredView) && (selectedView.TranslationX != 0)) { selectedView.TranslationX = 0; } } else { // Only move this view if it is not the parent view if (selectedView != monitoredView) { selectedView.TranslationX = deltaX; } } } touchConsumed = true; } } break; } case MotionEventActions.Up: { if (swiping == true) { // Assume no fling detected bool flingRightDetected = false; bool flingLeftDetected = false; // Assume a slow drag rather than a fast fling bool wasFlung = false; // Add the current movement to those held by the tracker and detemine the curent velocities velocity.AddMovement(touchEvent); velocity.ComputeCurrentVelocity(1000); float absXVelocity = Math.Abs(velocity.XVelocity); float absYVelocity = Math.Abs(velocity.YVelocity); float deltaX = touchEvent.RawX - initialDownX; // First of all detect a fling. // If the absolute velocity is greater than the fling minimum and the movement is still // in a mainly horizontal direction then its a fling. // Also ensure that the current delta is in the same direction as the fling, i.e. make sure that // the view has been repositioned back to where it started before processing a fling in the opposite // direction if ((absXVelocity > minimumFlingVelocity) && (absXVelocity > (absYVelocity * 2))) { // Check if the fling is in an allowed direction - may have changed direction since last move if (SwipingAllowed(velocity.XVelocity) == true) { // Make sure that the fling direction agrees with the current position of the view if (Math.Sign(velocity.XVelocity) == Math.Sign(deltaX)) { flingRightDetected = (velocity.XVelocity > 0); flingLeftDetected = (velocity.XVelocity < 0); wasFlung = true; } } } // More than half the width moved? else if ((SwipingAllowed(deltaX) == true) && (Math.Abs(deltaX) > (monitoredView.Width / 2))) { flingRightDetected = (deltaX > 0); flingLeftDetected = (deltaX < 0); } // Animate the selected view either to the right, left or back to the start // Work out whether the selected child or the parent view needs to be animated // Assume the child View animatedView = selectedView; if (((deltaX > 0) && (RightGroupSwipe == true)) || ((deltaX < 0) && (LeftGroupSwipe == true))) { animatedView = monitoredView; } // If the animated view has not changed position then skip the animation processing // Thius assumes that a velocity based fling will only occur after the view has // moved a little first TBD if (animatedView.TranslationX != 0) { if (flingRightDetected == true) { // Animate the view fully off to the right and report the event back to the view at the // end of the animation SimpleAnimate(animatedView, monitoredView.Width, new ObjectAnimatorListenerAdapter((animation) => { FlingRightHandler?.Invoke(this, new SwipeEventArgs { Position = selectedPosition, WasFlung = wasFlung }); if (animatedView != monitoredView) { animatedView.TranslationX = 0; } })); // If this is a parent view swipe and there's a left reveal then animate it across as well if ((animatedView == monitoredView) && (LeftRevealView != null)) { SimpleAnimate(LeftRevealView, 0, null); } } else if (flingLeftDetected == true) { // Animate the view fully off to the left and report the event back to the view at the // end of the animation SimpleAnimate(animatedView, -monitoredView.Width, new ObjectAnimatorListenerAdapter((animation) => { FlingLeftHandler?.Invoke(this, new SwipeEventArgs { Position = selectedPosition, WasFlung = wasFlung }); if (animatedView != monitoredView) { animatedView.TranslationX = 0; } })); // If this is a parent view swipe and there's a right reveal then animate it across as well if ((animatedView == monitoredView) && (RightRevealView != null)) { SimpleAnimate(RightRevealView, 0, null); } } else { // No fling so animate the views back to their starting positions SimpleAnimate(animatedView, 0, null); // If the parent view was being moved and there's a left or right review then animate them back // to their starting positions as well if (animatedView == monitoredView) { if ((deltaX > 0) && (LeftRevealView != null)) { // Animate the view back to the left SimpleAnimate(LeftRevealView, -monitoredView.Width, null); } if ((deltaX < 0) && (RightRevealView != null)) { // Animate the view back to the right SimpleAnimate(RightRevealView, monitoredView.Width, null); } } } } } // Reset state variables selectedView = null; swiping = false; // Free up the VelocityTracker if (velocity != null) { velocity.Recycle(); velocity = null; } break; } } return(touchConsumed); }
public override bool OnTouchEvent(MotionEvent e) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.Obtain(); } mVelocityTracker.AddMovement(e); MotionEventActions action = e.Action; if (action == MotionEventActions.Down) { x = e.GetX(); if (IsSlided()) { dispatched = DispatchTouchEventToView(GetChildAt(0), e); } else { dispatched = DispatchTouchEventToView(GetChildAt(1), e); } } else if (action == MotionEventActions.Move) { if (dispatched) { if (IsSlided()) { DispatchTouchEventToView(GetChildAt(0), e); } else { DispatchTouchEventToView(GetChildAt(1), e); } } else { float dx = e.GetX() - x; View view = this.GetChildAt(1); int left = (int)(view.Left + dx); if (left >= 0) { view.Layout(left, view.Top, view.Width + left, view.Top + view.Height); } } x = e.GetX(); } else if (action == MotionEventActions.Cancel || action == MotionEventActions.Up) { if (dispatched) { if (IsSlided()) { DispatchTouchEventToView(GetChildAt(0), e); } else { DispatchTouchEventToView(GetChildAt(1), e); } } else { mVelocityTracker.ComputeCurrentVelocity(1000); int velocityX = (int)mVelocityTracker.GetXVelocity(0); if (velocityX > VELOCITY_X_SPEED) { SetSlided(true); } else if (velocityX < -VELOCITY_X_SPEED) { SetSlided(false); } else { View view = GetChildAt(1); if (view.Left >= view.Width / 2) { SetSlided(true); } else { SetSlided(false); } } if (mVelocityTracker != null) { try { mVelocityTracker.Recycle(); } catch { } } } } else if (!IsSlided()) { DispatchTouchEventToView(GetChildAt(1), e); } return(true); }
public override bool OnTouchEvent(MotionEvent ev) { if (mIsVerbose) { Log.Verbose(TAG, "onTouchEvent: " + ((int)ev.Action & MotionEventCompat.ActionMask)); } if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.Obtain(); } mVelocityTracker.AddMovement(ev); var action = ev.Action; switch ((int)action & MotionEventCompat.ActionMask) { case (int)MotionEventActions.Down: // If being flinged and user touches, stop the fling. isFinished // will be false if being flinged. if (!mScroller.IsFinished) { mScroller.AbortAnimation(); } // Remember where the motion event started mDownMotionX = ev.GetX(); mDownMotionY = ev.GetY(); mDownScrollX = ScrollX; mActivePointerId = MotionEventCompat.GetPointerId(ev, 0); break; case (int)MotionEventActions.Move: if (mIsVerbose) { Log.Verbose(TAG, "mTouchState=" + mTouchState); } if (mTouchState == TOUCH_STATE_SCROLLING) { // Scroll to follow the motion event int pointerIndex = MotionEventCompat.FindPointerIndex(ev, mActivePointerId); float x = MotionEventCompat.GetX(ev, pointerIndex); View lastChild = GetChildAt(ChildCount - 1); int maxScrollX = lastChild.Right - Width; ScrollTo(Math.Max(0, Math.Min(maxScrollX, (int)(mDownScrollX + mDownMotionX - x ))), 0); if (mOnScrollListener != null) { mOnScrollListener.OnScroll(GetCurrentScreenFraction()); } } else if (mTouchState == TOUCH_STATE_REST) { if (mLocked) { // we're locked on the current screen, don't allow moving break; } /* * Locally do absolute value. mLastMotionX is set to the y value * of the down event. */ int pointerIndex = MotionEventCompat.FindPointerIndex(ev, mActivePointerId); float x = MotionEventCompat.GetX(ev, pointerIndex); float y = MotionEventCompat.GetY(ev, pointerIndex); int xDiff = (int)Math.Abs(x - mDownMotionX); int yDiff = (int)Math.Abs(y - mDownMotionY); bool xPaged = xDiff > mPagingTouchSlop; bool xMoved = xDiff > mTouchSlop; bool yMoved = yDiff > mTouchSlop; if (xMoved || yMoved) { if (xPaged) { // Scroll if the user moved far enough along the X axis mTouchState = TOUCH_STATE_SCROLLING; } // Either way, cancel any pending longpress if (mAllowLongPress) { mAllowLongPress = false; // Try canceling the long press. It could also have been scheduled // by a distant descendant, so use the mAllowLongPress flag to block // everything View currentScreen = GetScreenAt(mCurrentScreen); if (currentScreen != null) { currentScreen.CancelLongPress(); } } } } break; case (int)MotionEventActions.Up: if (mTouchState == TOUCH_STATE_SCROLLING) { int activePointerId = mActivePointerId; int pointerIndex = MotionEventCompat.FindPointerIndex(ev, activePointerId); float x = MotionEventCompat.GetX(ev, pointerIndex); VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.ComputeCurrentVelocity(1000, mMaximumVelocity); //TODO(minsdk8): int velocityX = (int) MotionEventUtils.getXVelocity(velocityTracker, activePointerId); int velocityX = (int)velocityTracker.XVelocity; bool isFling = Math.Abs(mDownMotionX - x) > MIN_LENGTH_FOR_FLING; float scrolledPos = GetCurrentScreenFraction(); int whichScreen = Math.Round(scrolledPos); if (isFling && mIsVerbose) { Log.Verbose(TAG, "isFling, whichScreen=" + whichScreen + " scrolledPos=" + scrolledPos + " mCurrentScreen=" + mCurrentScreen + " velocityX=" + velocityX); } if (isFling && velocityX > SNAP_VELOCITY && mCurrentScreen > 0) { // Fling hard enough to move left // Don't fling across more than one screen at a time. int bound = scrolledPos <= whichScreen ? mCurrentScreen - 1 : mCurrentScreen; SnapToScreen(Math.Min(whichScreen, bound)); } else if (isFling && velocityX < -SNAP_VELOCITY && mCurrentScreen < ChildCount - 1) { // Fling hard enough to move right // Don't fling across more than one screen at a time. int bound = scrolledPos >= whichScreen ? mCurrentScreen + 1 : mCurrentScreen; SnapToScreen(Math.Max(whichScreen, bound)); } else { SnapToDestination(); } } else { PerformClick(); } mTouchState = TOUCH_STATE_REST; mActivePointerId = INVALID_POINTER; // Can't do this -> // Intentially fall through to cancel mTouchState = TOUCH_STATE_REST; mActivePointerId = INVALID_POINTER; if (mVelocityTracker != null) { mVelocityTracker.Recycle(); mVelocityTracker = null; } break; case (int)MotionEventActions.Cancel: mTouchState = TOUCH_STATE_REST; mActivePointerId = INVALID_POINTER; if (mVelocityTracker != null) { mVelocityTracker.Recycle(); mVelocityTracker = null; } break; case (int)MotionEventCompat.ActionPointerUp: OnSecondaryPointerUp(ev); break; } return(true); }
public override bool OnInterceptTouchEvent(MotionEvent ev) { /* * This method JUST determines whether we want to intercept the motion. * If we return true, onTouchEvent will be called and we do the actual * scrolling there. */ // Begin tracking velocity even before we have intercepted touch events. if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.Obtain(); } mVelocityTracker.AddMovement(ev); /* * Shortcut the most recurring case: the user is in the dragging * state and he is moving his finger. We want to intercept this * motion. */ var action = ev.Action; if (mIsVerbose) { Log.Verbose(TAG, "onInterceptTouchEvent: " + (ev.Action & MotionEventActions.Mask)); } if (((action & MotionEventActions.Mask) == MotionEventActions.Move) && (mTouchState == TOUCH_STATE_SCROLLING)) { if (mIsVerbose) { Log.Verbose(TAG, "Intercepting touch events"); } return(true); } switch (action & MotionEventActions.Mask) { case MotionEventActions.Move: { if (mLocked) { // we're locked on the current screen, don't allow moving break; } /* * Locally do absolute value. mDownMotionX is set to the y value * of the down event. */ int pointerIndex = MotionEventCompat.FindPointerIndex(ev, mActivePointerId); float x = MotionEventCompat.GetX(ev, pointerIndex); float y = MotionEventCompat.GetY(ev, pointerIndex); int xDiff = (int)Java.Lang.Math.Abs(x - mDownMotionX); int yDiff = (int)Java.Lang.Math.Abs(y - mDownMotionY); bool xPaged = xDiff > mPagingTouchSlop; bool xMoved = xDiff > mTouchSlop; bool yMoved = yDiff > mTouchSlop; if (xMoved || yMoved) { if (xPaged) { // Scroll if the user moved far enough along the X axis mTouchState = TOUCH_STATE_SCROLLING; } // Either way, cancel any pending longpress if (mAllowLongPress) { mAllowLongPress = false; // Try canceling the long press. It could also have been scheduled // by a distant descendant, so use the mAllowLongPress flag to block // everything View currentScreen = GetScreenAt(mCurrentScreen); if (currentScreen != null) { currentScreen.CancelLongPress(); } } } break; } case MotionEventActions.Down: { float x = ev.GetX(); float y = ev.GetY(); // Remember location of down touch mDownMotionX = x; mDownMotionY = y; mDownScrollX = ScrollX; mActivePointerId = MotionEventCompat.GetPointerId(ev, 0); mAllowLongPress = true; /* * If being flinged and user touches the screen, initiate drag; * otherwise don't. mScroller.isFinished should be false when * being flinged. */ mTouchState = mScroller.IsFinished ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING; break; } case MotionEventActions.Cancel: case MotionEventActions.Up: // Release the drag mTouchState = TOUCH_STATE_REST; mAllowLongPress = false; mActivePointerId = INVALID_POINTER; if (mVelocityTracker == null) { mVelocityTracker.Recycle(); mVelocityTracker = null; } break; case MotionEventActions.PointerUp: OnSecondaryPointerUp(ev); break; } /* * The only time we want to intercept motion events is if we are in the * drag mode. */ bool intercept = mTouchState != TOUCH_STATE_REST; if (mIsVerbose) { Log.Verbose(TAG, "Intercepting touch events: " + intercept); } return(intercept); }
public virtual bool OnTouchEvent(Android.Views.MotionEvent ev) { switch (ev.Action) { case MotionEventActions.Down: { mVelocityTracker = VelocityTracker.Obtain(); if (null != mVelocityTracker) { mVelocityTracker.AddMovement(ev); } else { Log.Info(LOG_TAG, "Velocity tracker is null"); } mLastTouchX = GetActiveX(ev); mLastTouchY = GetActiveY(ev); mIsDragging = false; break; } case MotionEventActions.Move: { float x = GetActiveX(ev); float y = GetActiveY(ev); float dx = x - mLastTouchX, dy = y - mLastTouchY; if (!mIsDragging) { // Use Pythagoras to see if drag length is larger than // touch slop mIsDragging = FloatMath.Sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; } if (mIsDragging) { mListener.OnDrag(dx, dy); mLastTouchX = x; mLastTouchY = y; if (null != mVelocityTracker) { mVelocityTracker.AddMovement(ev); } } break; } case MotionEventActions.Cancel: { // Recycle Velocity Tracker if (null != mVelocityTracker) { mVelocityTracker.Recycle(); mVelocityTracker = null; } break; } case MotionEventActions.Up: { if (mIsDragging) { if (null != mVelocityTracker) { mLastTouchX = GetActiveX(ev); mLastTouchY = GetActiveY(ev); // Compute velocity within the last 1000ms mVelocityTracker.AddMovement(ev); mVelocityTracker.ComputeCurrentVelocity(1000); float vX = mVelocityTracker.GetXVelocity(0), vY = mVelocityTracker .GetYVelocity(0); // If the velocity is greater than minVelocity, call // listener if (Math.Max(Math.Abs(vX), Math.Abs(vY)) >= mMinimumVelocity) { mListener.OnFling(mLastTouchX, mLastTouchY, -vX, -vY); } } } // Recycle Velocity Tracker if (null != mVelocityTracker) { mVelocityTracker.Recycle(); mVelocityTracker = null; } break; } } return(true); }