开发者

How to implement one-finger rotate gesture recognizer?

I'm aware that there's the UIRotateGestureRecognizer already part of the iOS. But this gesture required two fingers. How I can implement a similar gesture recognizer requiring 开发者_开发知识库only one finger? There's a game in the AppStore - Gyrotate with a pretty good implementation of this. Any clues are appreciated. Thx.


Kirby Turner has a complete one finger rotation gesture recognizer here.


Here's the code - it works on my simulator. Mark answered if that is what you were looking for.

    // On new touch, start a new array of points
- (void) touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event
{
    self.points = [NSMutableArray array];
    CGPoint pt = [[touches anyObject] locationInView:self];
    [self.points addObject:[NSValue valueWithCGPoint:pt]];
}

// Add each point to the array
- (void) touchesMoved:(NSSet *) touches withEvent:(UIEvent *) event
{
    CGPoint pt = [[touches anyObject] locationInView:self];
    [self.points addObject:[NSValue valueWithCGPoint:pt]];
    [self setNeedsDisplay];
}

// At the end of touches, determine whether a circle was drawn
- (void) touchesEnded:(NSSet *) touches withEvent:(UIEvent *) event
{
    if (!self.points) return;
    if (self.points.count < 3) return;

    // Test 1: The start and end points must be between 60 pixels of each other
    CGRect tcircle;
    if (distance(POINT(0), POINT(self.points.count - 1)) < 60.0f)
        tcircle = [self centeredRectangle];

    // Test 2: Count the distance traveled in degrees. Must fall within 45 degrees of 2 PI
    CGPoint center = CGPointMake(CGRectGetMidX(tcircle), CGRectGetMidY(tcircle));
    float distance = ABS(acos(dotproduct(centerPoint(POINT(0), center), centerPoint(POINT(1), center))));
    for (int i = 1; i < (self.points.count - 1); i++)
        distance += ABS(acos(dotproduct(centerPoint(POINT(i), center), centerPoint(POINT(i+1), center))));
    if ((ABS(distance - 2 * M_PI) < (M_PI / 4.0f))) circle = tcircle;

    [self setNeedsDisplay];
}


I implemented IQStickerView with OneFingerRotation, Scale, Resize and Close feature.

Features:-

1) One Finger Rotation Scale.

2) One Finger Resize.

3) Enable/Desable Rotation, Scale, Resize with properties.

4) Auto manage Multiple IQStickerView.

5) Can work with UIScrollView also.

6) Fast Responsiveness.

github repositor is here:- https://github.com/hackiftekhar/IQStickerView


Try exploring UIGestureRecognizer Class. You should be able to customize it using UIGestureRecognizerDelegate


Implemented with pan gesture recogniser, this is using another UIView that the gesture recogniser is attached to but it should work with it attached to the view you want to rotate.

- (void) gestureRotateButtonPan:(UIPanGestureRecognizer*) gestureRecognizer {

    switch (gestureRecognizer.state) {
        case UIGestureRecognizerStatePossible:
            break;
        case UIGestureRecognizerStateBegan:
        {
            CGPoint location = [gestureRecognizer translationInView:[gestureRecognizer view]];
            _touchRotateStartPoint = [self convertPoint:location fromView:[gestureRecognizer view]];
        }
            break;
        case UIGestureRecognizerStateChanged:
        {
            CGPoint imageLocation = CGPointMake(self.mainImageView.transform.tx + self.mainImageView.center.x
                                                , self.mainImageView.transform.ty + self.mainImageView.center.y);
            CGPoint buttonLocation = [gestureRecognizer translationInView:self];
            buttonLocation.x += _touchRotateStartPoint.x;
            buttonLocation.y += _touchRotateStartPoint.y;

            CGFloat currentRotation = atan2(buttonLocation.y - imageLocation.y, buttonLocation.x - imageLocation.x)
                                        - atan2(_touchRotateStartPoint.y - imageLocation.y, _touchRotateStartPoint.x - imageLocation.x);

            CGFloat rotation = -(_lastRotation - currentRotation);
            CGAffineTransform currentTransform = self.mainImageView.transform;
            CGAffineTransform rotatedTransform = CGAffineTransformRotate(currentTransform, rotation);
            self.mainImageView.transform = rotatedTransform;

            [self setNeedsDisplay];
        }
            break;
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateEnded:
            _lastRotation = 0.0;
            break;
        case UIGestureRecognizerStateFailed:
            break;
        default:
            break;
    }
}


One Finger Rotation on UIView using PanGestureRecogniser

Fully Functional code with Swift5

import UIKit

class ViewController: UIViewController {
    
    //Variable for rotating
    private var deltaAngle:CGFloat = 0
    
    let squareView : UIView = {
        let anyView = UIView()
        anyView.backgroundColor = .red
        anyView.isUserInteractionEnabled = true
        anyView.isMultipleTouchEnabled = true
        return anyView
        
    }()
    
    let rotateButton : UIButton = {
        let button = UIButton()
        button.backgroundColor = .black
        button.setImage(UIImage(systemName: "rotate.right"), for: .normal)
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        squareView.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
        rotateButton.frame = CGRect(x: 0, y: squareView.frame.height-30, width: 30, height: 30)
        squareView.center = view.center
        view.addSubview(squareView)
        squareView.addSubview(rotateButton)
        
        let PanToRotate = UIPanGestureRecognizer(target: self, action: #selector(handleRotateGesture(_:)))
        rotateButton.addGestureRecognizer(PanToRotate)
        
    }
    
    
    
    
    @objc func handleRotateGesture(_ recognizer : UIPanGestureRecognizer){
        let touchLocation = recognizer.location(in: squareView.superview)
        
        let center = squareView.center
        
        switch recognizer.state{
            
        case .began :
            self.deltaAngle = atan2(touchLocation.y - center.y, touchLocation.x - center.x) - atan2(squareView.transform.b, squareView.transform.a)
            
        case .changed:
            let angle = atan2(touchLocation.y - center.y, touchLocation.x - center.x)
            
            let angleDiff = self.deltaAngle - angle
            
            squareView.transform = CGAffineTransform(rotationAngle: -angleDiff)
                        
        default: break
            
        }
        
    }
    
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜