如何编写单指旋转手势类

527 阅读2分钟

这里用pan手势实现旋转功能

  1. 新建New->File->Cocoa Touch Class
  1. .h文件继承手势类UIGestureRecognizer
#import <UIKit/UIKit.h>
@interface KTOneFingerRotationGestureRecognizer : UIGestureRecognizer 
{   
}
/**
 The rotation of the gesture in radians since its last change.
 */
@property (nonatomic, assign) CGFloat rotation;
@end

接下来我会分析UIGestureRecognizer:UIGestureRecognizer.h分析

最重要的是它的子类UIGestureRecognizerSubclass.h:UIGestureRecognizerSubclass.h分析

  1. .m文件实现手势方法
#import "KTOneFingerRotationGestureRecognizer.h"//非常重要引用这个类
#import <UIKit/UIGestureRecognizerSubclass.h>

@implementation KTOneFingerRotationGestureRecognizer

@synthesize rotation = rotation_;

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   // Fail when more than 1 finger detected.
   if ([[event touchesForGestureRecognizer:self] count] > 1) {
      [self setState:UIGestureRecognizerStateFailed];
   }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    //UIGestureRecognizerStatePossible:The gesture recognizer has not
    //yet recognized its gesture, but may be evaluating touch events. 
    //This is the default state.
   if ([self state] == UIGestureRecognizerStatePossible) {
      [self setState:UIGestureRecognizerStateBegan];
   } else {
      [self setState:UIGestureRecognizerStateChanged];
   }

   // We can look at any touch object since we know we 
   // have only 1. If there were more than 1 then 
   // touchesBegan:withEvent: would have failed the recognizer.
   UITouch *touch = [touches anyObject];

   // To rotate with one finger, we simulate a second finger.
   // The second figure is on the opposite side of the virtual
   // circle that represents the rotation gesture.

   UIView *view = [self view];
   CGPoint center = CGPointMake(CGRectGetMidX([view bounds]), CGRectGetMidY([view bounds]));
   CGPoint currentTouchPoint = [touch locationInView:view];//找到触碰点在视图中位置
   CGPoint previousTouchPoint = [touch previousLocationInView:view];//上一个触碰点在视图位置
   
   //反正切:范围在-pi/2~pi/2,因此可以分出顺逆时针
   //看流程图:可以得到现在点的正切角-上一个点的正切角等于旋转后的角度
   CGFloat angleInRadians = atan2f(currentTouchPoint.y - center.y, currentTouchPoint.x - center.x) - atan2f(previousTouchPoint.y - center.y, previousTouchPoint.x - center.x);
   
   [self setRotation:angleInRadians];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
   // Perform final check to make sure a tap was not misinterpreted.
   if ([self state] == UIGestureRecognizerStateChanged) {
      [self setState:UIGestureRecognizerStateEnded];
   } else {
      [self setState:UIGestureRecognizerStateFailed];
   }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
   [self setState:UIGestureRecognizerStateFailed];
}

@end

反正切求旋转角度

  1. 实现思路

实现效果

(1)关闭右下角按钮的互动:

 self.zoomButton.userInteractionEnabled = NO;//是否开启用户事件

(2)用masonry自动布局沿着旋转按钮的右边和底部建立旋转view,并给他增加旋转手势

//旋转view
    [self.rotationView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(self.zoomButton).mas_offset(-2*buttonWidthAndHeight);
        make.right.mas_equalTo(self.zoomButton);
        make.top.mas_equalTo(self.zoomButton).mas_offset(-2*buttonWidthAndHeight);
        make.bottom.mas_equalTo(self.zoomButton);
    }];
    KTOneFingerRotationGestureRecognizer *rotation = [[KTOneFingerRotationGestureRecognizer alloc] initWithTarget:self action: @selector(rotating:)];
    [self addGestureRecognizer:rotation];

(3)旋转动作实现:

判断接触点是否在旋转view上,如果在则进行旋转

//旋转实现
- (void)rotating:(KTOneFingerRotationGestureRecognizer *)recognizer
{
    //获得触碰点在view上的位置
    CGPoint point = [recognizer locationInView:self];
//    point = [self.rotationView.layer convertPoint:point fromLayer:self.layer];
    NSLog(@"进行旋转:point=%f,%f",point.x,point.y);
    //判断点是否在旋转视图上
    BOOL result = [self.rotationView.layer containsPoint:point];//self.layer->self.rotationView.layer?
    if (!result) {
        NSLog(@"Not in button");
        return;
    }
    //如果在进行旋转
   [self setTransform:CGAffineTransformRotate([self transform], [recognizer rotation])];
    NSLog(@" [recognizer rotation]=%f", [recognizer rotation]);
    if (self.rotationBlock) {
        self.rotationBlock([recognizer rotation]);//这里设置字体随框旋转,需要api接口,就不放上来了
    }
}