学习苹果UIGestureRecognizer 相关demo

商开济
2023-12-01


gesture分类



遗留问题

关于使用CTM 旋转、缩放对子视图和父视图相关坐标的影响。

相关功能

对view的拖动、缩放、旋转功能

关键代码(值得注意学习的地方标注在注释中)

// adds a set of gesture recognizers to one of our piece subviews
- (void)addGestureRecognizersToPiece:(UIView *)piece
{
    UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotatePiece:)];
    [piece addGestureRecognizer:rotationGesture];

    
    UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scalePiece:)];
    [pinchGesture setDelegate:self];
    [piece addGestureRecognizer:pinchGesture];

    
    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panPiece:)];
    [panGesture setMaximumNumberOfTouches:2];
    [panGesture setDelegate:self];
    [piece addGestureRecognizer:panGesture];
    
    UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(showResetMenu:)];
    [piece addGestureRecognizer:longPressGesture];
}

-(id)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame])
    {
        firstPieceView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 90, 200, 200)];
        [self addSubview:firstPieceView];
        firstPieceView.userInteractionEnabled = YES;
        firstPieceView.image = [UIImage imageNamed:@"YellowSquare.png"];
        [self addSubview:firstPieceView];
        
        secondPieceView = [[UIImageView alloc] initWithFrame:CGRectMake(110,190, 100, 100)];
        [self addSubview:secondPieceView];
        secondPieceView.userInteractionEnabled = YES;
        secondPieceView.image = [UIImage imageNamed:@"CyanSquare.png"];
        [self addSubview:secondPieceView];
        
        thirdPieceView = [[UIImageView alloc] initWithFrame:CGRectMake(210, 290, 100, 100)];
        [self addSubview:thirdPieceView];
        thirdPieceView.userInteractionEnabled = YES;
        thirdPieceView.image = [UIImage imageNamed:@"MagentaSquare.png"];
        [self addSubview:thirdPieceView];
        
        [self addGesture];
    }
    return self;
}

- (void)addGesture
{
    [self addGestureRecognizersToPiece:firstPieceView];
    [self addGestureRecognizersToPiece:secondPieceView];
    [self addGestureRecognizersToPiece:thirdPieceView];
}


#pragma mark -
#pragma mark === Touch handling  ===
#pragma mark

// shift the piece's center by the pan amount
// reset the gesture recognizer's translation to {0, 0} after applying so the next callback is a delta from the current position

//各个pieceview之间的层次结构,由addsubview的先后顺序决定
- (void)panPiece:(UIPanGestureRecognizer *)gestureRecognizer
{
    [self adjustAnchorPointForGestureRecognizer:gestureRecognizer];
    UIView *panView = gestureRecognizer.view;
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan || gestureRecognizer.state == UIGestureRecognizerStateChanged)
    {
        
        //移动的距离
        CGPoint trasitionDistance = [gestureRecognizer translationInView:panView.superview];
        CGPoint transionDistance2 = [gestureRecognizer translationInView:panView];
        //pieceview坐标应该变化的距离
        //问题:scale之后,返回的trasitionDistance,transionDistance2是不一样的
        panView.center = CGPointMake(panView.center.x + trasitionDistance.x, panView.center.y + trasitionDistance.y);
        //transion归0,这样每次调用返回的就是增量
        [gestureRecognizer setTranslation:CGPointZero inView:panView];
    }
}

// rotate the piece by the current rotation
// reset the gesture recognizer's rotation to 0 after applying so the next callback is a delta from the current rotation
- (void)rotatePiece:(UIRotationGestureRecognizer *)gestureRecognizer
{
    [self adjustAnchorPointForGestureRecognizer:gestureRecognizer];
     UIView *panView = gestureRecognizer.view;
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan || gestureRecognizer.state == UIGestureRecognizerStateChanged)
    {
        CGFloat rotation = gestureRecognizer.rotation;
        
        //最关键的问题CGAffineTransformRotate变化之后,对坐标和锚点的影响
        panView.transform = CGAffineTransformRotate(panView.transform, rotation);
        [gestureRecognizer setRotation:0];
    }
}

// scale the piece by the current scale
// reset the gesture recognizer's rotation to 0 after applying so the next callback is a delta from the current scale

- (void)scalePiece:(UIPinchGestureRecognizer *)gestureRecognizer
{//注意缩放之后,描点也会改变
    [self adjustAnchorPointForGestureRecognizer:gestureRecognizer];
    UIView *panView = gestureRecognizer.view;
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan || gestureRecognizer.state == UIGestureRecognizerStateChanged)
    {
        CGFloat scale = gestureRecognizer.scale;
        panView.transform = CGAffineTransformScale(panView.transform,scale, scale);
        [gestureRecognizer setScale:1];
    }
}

- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        UIView *piece = gestureRecognizer.view;
        CGPoint locationInView = [gestureRecognizer locationInView:piece];
        CGPoint locationInSuperview = [gestureRecognizer locationInView:piece.superview];
        
        piece.layer.anchorPoint = CGPointMake(locationInView.x / piece.bounds.size.width,
                                              locationInView.y / piece.bounds.size.height);
        piece.center = locationInSuperview;
    }
}

-(void)showResetMenu:(UILongPressGestureRecognizer *)gesture
{
    //此方法,在不同的状态都会回调,所有要对状态进行判断
    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        UIMenuController *menuController = [UIMenuController sharedMenuController];
        [menuController setMenuVisible:YES animated:YES];
        UIMenuItem *item = [[UIMenuItem alloc] initWithTitle:@"reset" action:@selector(reset:)];
        UIMenuItem *item2 = [[UIMenuItem alloc] initWithTitle:@"reset" action:@selector(reset:)];
        NSArray *array = [NSArray arrayWithObjects:item,item2, nil];
        menuController.menuItems = array;
        [self becomeFirstResponder];
        CGPoint point = [gesture locationInView:gesture.view];
        [menuController setTargetRect:CGRectMake(point.x, point.y, 100, 40)     inView:gesture.view];
        pieceForReset = gesture.view;
    }
}


 类似资料: