androidgesturedetectoronfling

Android - How to spin the image


I have an image and its in imageView. I want to add a functionally that allows users to spin the image if they try to spin it to the right side.For example if user tries to spin it to the left side, it doesnt spin.

enter image description here

This is my spinwheel.

I tried to use GestureDetector and onFling event but it wasn't enough for me to detect if user tries to spin it to the right side or left side. How can i do this ?

Edit:

            var normalVectorX = e2?.x!! - 515
            var normalVectorY = e2?.y!! - 515

            var tangentVectorX  = -normalVectorY
            var tangentVectorY = normalVectorX

            var tangentVectorLength = (Math.sqrt(Math.pow((515 - e2?.y!!).toDouble(), 2.0)) + Math.pow((e2?.x!! - 515).toDouble(), 2.0))

            var unitTangentX = tangentVectorX / tangentVectorLength
            var unitTangentY = tangentVectorY / tangentVectorLength

            var scalarProjection = (velocityX * unitTangentX) + (velocityY * unitTangentY)

            if (scalarProjection > 0) // Right Side
                spinWheel((spinCountX * 360).toFloat() + 360 - (mPrizeIndex * 60) , 12000)

This is the code implementation based on the pseudo code of answer. 515 = center of the wheel.


Solution

  • onFling gives you the MotionEvents of the corresponding fling gesture. You can then call getX(int) and getY(int) to get the coordinates.

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
      float x = e2.getX(0);  // Assuming you only care about the first finger
      float y = e2.getY(0);
      if (x < imageView.getWidth() / 2) {
        // fling is on the left side
      } else {
        // fling is on the right side
      }
    }
    

    Side note: I think the code above will behave unnaturally if the fling is horizontal. If you want your spin gesture to be more realistic, I think you will be better off calculating the tangential component.

    Edit: Here's how you would calculate the tangential component.

    You would want to calculate the scalar projection of the velocity vector on the unit tangent of the circle at the point where the touch event is.

    Pseudo code:

    velocityVector = (velocityX, velocityY)
    locationOfTouch = (e2.getX(0), e2.getY(0))
    centerOfWheel = (166, 155)  # Measured from your image
    normalVector = locationOfTouch - centerOfWheel
                 = (locationOfTouch.x - centerOfWheel.x, locationOfTouch.y - centerOfWheel.y)
    

    To get the clockwise tangent vector, we take the normalVector, swap the X and Y components, and negate the X (from 2D Euclidean vector rotations).

    tangentVector = (-normalVector.y, normalVector.x)
    unitTangent = tangentVector / tangentVector.length()
    

    Finally, you take the dot product to get the scalar projection:

    scalarProjection = velocityVector.dotProduct(unitTangent)
                     = (velocityVector.x * unitTangent.x) + (velocityVector.y * unitTangent.y)
    

    If scalarProjection is positive, that means the fling gesture is in the clockwise direction. If it is negative, that means the gesture is in anti-clockwise direction.

    As a bonus, since we used the unit tangent, the resulting scalar projection also represents how fast the fling is in the clockwise direction, so you can change the spin animation to be faster or slower, or set a threshold such that a small velocity in that direction doesn't trigger the wheel to spin.

    enter image description here