protected virtual void OnDisplayLinkLoop() { if (link == null || viewPort == null) { return; } var actualFrameDuration = link.TargetTimestamp - link.Timestamp; var decelerationEllapsedTime = link.Timestamp - decelerationStartTime; double frameOffsetX, frameOffsetY; if (Math.Abs(decelerationVelocityX) > 0) { var framePositionX = decelerationVelocityX * decelerationEllapsedTime - decelerationX * Math.Pow(decelerationEllapsedTime, 2) / 2; frameOffsetX = framePositionX - lastDecelerationFramePositionX; lastDecelerationFramePositionX = framePositionX; if (Math.Abs(decelerationVelocityX) - Math.Abs(decelerationX * decelerationEllapsedTime) <= 1) { decelerationVelocityX = 0; } } else { frameOffsetX = 0; } if (Math.Abs(decelerationVelocityY) > 0) { var framePositionY = decelerationVelocityY * decelerationEllapsedTime - decelerationY * Math.Pow(decelerationEllapsedTime, 2) / 2; frameOffsetY = framePositionY - lastDecelerationFramePositionY; lastDecelerationFramePositionY = framePositionY; if (Math.Abs(decelerationVelocityY) - Math.Abs(decelerationY * decelerationEllapsedTime) <= 1) { decelerationVelocityY = 0; } } else { frameOffsetY = 0; } var movementVector = new CGPoint(frameOffsetX, frameOffsetY); var success = viewPort.Offset(movementVector); if (!success) { var movementDirections = GetVectorDirection(movementVector); decelerationVelocityX = viewPort.CanMove(movementDirections & Direction.Horizontal) ? decelerationVelocityX : 0; decelerationVelocityY = viewPort.CanMove(movementDirections & Direction.Vertical) ? decelerationVelocityY : 0; } if (decelerationEllapsedTime > 0.3f && Math.Abs(frameOffsetX) < 0.1 && Math.Abs(frameOffsetY) < 0.1) { StopDeceleration(); } FireRedrawIsNeeded(); }