Search code examples
androidimageviewdraggableimage-rotation

Android: Rotate image by dragging a specific part of it


I have this ImageView:

enter image description here

I need to be able to rotate the whole image (The circle and the two "30" circles) when I drag the outside circles around. It should rotate only if I start dragging from the outside "30" circles

They should all rotate around the dot in the center.

I managed to make this image rotate when I drag it in any part of it using a View.OnTouchListener and by calculating the angle between the touch event coordinates and the pivot point, and then rotate the imageView.

How can I detect when the motion event is in the outer circles only, to prevent the image from rotating when dragging inside the big circle?


Solution

  • In OnTouchListener's onTouchEvent method, you can utilize the ACTION_DOWN event to check, if a TouchEvent starts inside the little outer circles. If this is true, set a boolean to true. In the ACTION_MOVE event, you just have to check the boolean and only rotate if it is set to true. Then, use ACTION_UP and ACTION_CANCEL to set the boolean to false again.

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int)event.getX();
        int y = (int)event.getY();
        boolean rightPosition = false;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // When the event is in the little circles rightPosition=true
                break;
            case MotionEvent.ACTION_MOVE:
                if(rightPosition) yourRotationCode();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                rightPosition = false;
        }
    return false;
    }
    

    How do you know, if the drag starts in the little circles?

    Tl;dr: Keep track of the polar coordinates of the little circles and compare them with the ACTION_DOWN event's coordinates.

    To determine, if the ACTION_DOWN event occurs inside the little circles, keep track of the angle, your ImageView is rotated from it's 'zero position'. In the beginning, the little circles are at 45° and 125°. Offset them against the current rotation of your ImageView, get the angle between 12 o'clock and the ACTION_DOWN event and compare them. Also take into account the distance between the point of rotation and the event. As you already calculate the needed rotation, I think you know how to determine these angles.
    The right distance from the point of rotation should be calculated from the ImageView's height and width, so you remain density independent. This needs some pixel counting and calculating the ratio, based on the original image resource, done by hand. This ratio can then be hard coded to a constant value.
    As the position of an TouchEvent is precise to one pixel, you should add some offset around the calculated center of the little circles. I would recommend a square around the little circle. Its side length has again to be calculated in aspect to the ImageView's height and width. Again you can determine the ratio of your 'valid area' to the size of the ImageView by hand and provide it as a constant. Then you just have to check if the starting point's coordinates are within +/-(side length / 2) of the center of the little circles.