相同的CGAffineTransform不同的锚点

时间:2011-11-23 12:21:59

标签: objective-c cgaffinetransform

我有1个视图,包含2个子视图。其中一个比另一个大10倍。我有一个大手势识别器(位于顶部)。

我希望能够通过手指之间的锚点捏合手势来缩放大一个。我希望小家伙能够从相同的全球位置锚点进行相同的变换,但不会改变自己的锚点。

希望我自己解释一下。这是代码:

- (void)twoFingerPinch:(UIPinchGestureRecognizer *)gestureRecognizer
{    
    //this changes the anchor point of "big" without moving it
    [self adjustAnchorPointForGestureRecognizer:gestureRecognizer];

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {    

        CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
        float scale = sqrt(transform.a*transform.a+transform.c*transform.c);

        //this transforms "big"
        [gestureRecognizer view].transform = transform;

        //anchor point location in little view
        CGPoint pivote = [gestureRecognizer locationInView:little];

        CGAffineTransform transform_t = CGAffineTransformConcat(CGAffineTransformMakeTranslation(-pivote.x, -pivote.y), transform);
        transform_t = CGAffineTransformConcat(transform_t, CGAffineTransformMakeTranslation(pivote.x, pivote.y));

        little.transform = transform_t;
    }
    [gestureRecognizer setScale:1];
}

但这不起作用,小视图不断跳跃并疯狂。

编辑:更多信息。

好的,这是图表:diagram

红色方块是大视图,黑色方块是小视图。虚线方块是主视图。

该行:[self adjustAnchorPointForGestureRecognizer:gestureRecognizer];将大视图锚点更改为捏手势的中心。这很有效。

当我缩放大视图时,小视图应缩放相同的数量并移动,使其在大视图中居中,就像现在一样。也就是说,它应该使用与大视图相同的锚点进行缩放。

如果可能的话,我想将这些转换保留在CGAffineTransform中的小视图中。

2 个答案:

答案 0 :(得分:2)

好的,我终于找到了它。我不知道这是否是更好的解决方案,但它确实有效。

- (void)twoFingerPinch:(UIPinchGestureRecognizer *)gestureRecognizer
{    
    [self adjustAnchorPointForGestureRecognizer:gestureRecognizer];

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {    

        CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
        float scale = sqrt(transform.a*transform.a+transform.c*transform.c);
        if((scale>0.1)&&(scale<20)) {

            [gestureRecognizer view].transform = transform;

            CGPoint anchor = [gestureRecognizer locationInView:little];
            anchor = CGPointMake(anchor.x - little.bounds.size.width/2, anchor.y-little.bounds.size.height/2);

            CGAffineTransform affineMatrix = little.transform;
            affineMatrix = CGAffineTransformTranslate(affineMatrix, anchor.x, anchor.y);
            affineMatrix = CGAffineTransformScale(affineMatrix, [gestureRecognizer scale], [gestureRecognizer scale]);
            affineMatrix = CGAffineTransformTranslate(affineMatrix, -anchor.x, -anchor.y);        
            little.transform = affineMatrix;    

            [eagleView setTransform:little.transform];    
            [gestureRecognizer setScale:1];
        }

    }
}

那个eaglView系列,是我需要CGAffineTransform并且无法更改锚点的真正原因。我将它发送到OpenGL来改变模型视图变换矩阵。

现在,通过用户反馈,它可以同时完成3种变换(旋转,缩放,平移)。

修改

只是一点注意:似乎当我移动视图太快时,eaglView和UIView会失去同步。所以我不直接将变换应用于UIViews,我将它们与eaglView中的信息一起应用。像这样:

- (void)twoFingerPinch:(UIPinchGestureRecognizer *)gestureRecognizer
{    
    [self adjustAnchorPointForGestureRecognizer:gestureRecognizer];

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {    

        CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
        float scale = sqrt(transform.a*transform.a+transform.c*transform.c);
        if((scale>0.1)&&(scale<20)) {

            //[gestureRecognizer view].transform = transform;

            CGPoint anchor = [gestureRecognizer locationInView:little];
            anchor = CGPointMake(anchor.x - little.bounds.size.width/2, anchor.y-little.bounds.size.height/2);

            CGAffineTransform affineMatrix = little.transform;
            affineMatrix = CGAffineTransformTranslate(affineMatrix, anchor.x, anchor.y);
            affineMatrix = CGAffineTransformScale(affineMatrix, [gestureRecognizer scale], [gestureRecognizer scale]);
            affineMatrix = CGAffineTransformTranslate(affineMatrix, -anchor.x, -anchor.y);        
            //little.transform = affineMatrix;    

            [eagleView setTransform:affineMatrix];    
            [gestureRecognizer setScale:1];

            CGAffineTransform transform = CGAffineTransformMakeRotation(eaglView.myRotation*M_PI/180);
            transform = CGAffineTransformConcat(CGAffineTransformMakeScale(eaglView.myScale, eaglView.myScale), transform);
            transform = CGAffineTransformConcat(transform, CGAffineTransformMakeTranslation(eaglView.myTranslate.x, -eaglView.myTranslate.y));    
            little.transform = transform;
            big.transform = transform;
        }

    }
}

答案 1 :(得分:0)

要使用捏合的中心作为锚点来缩放较小的视图,那么您需要手动计算新的位置:

CGRect frame = little.frame; // Returns the frame based on the current transform
frame.origin.x = (frame.origin.x - pivot.x) * gestureRecognizer.scale;
frame.origin.y = (frame.origin.y - pivot.y) * gestureRecognizer.scale;
frame.width = frame.width * gestureRecognizer.scale;
frame.height = frame.height * gestureRecognizer.scale;

然后,更新转换。就个人而言,我会根据视图的实际位置而不是转换当前的变换来做到这一点 - 我觉得它更容易思考。例如:

little.transform = CGAffineTransformIndentity; // Remove the current transform
CGRect orgFrame = little.frame
CGFloat scale = frame.width / orgFrame.size.width;
CGAffineTransform t = CGAffineTransformMakeScale(scale, scale);
t = CGAffineTransformConcat(t, CGAffineTransformMakeTranslation(newFrame.origin.x - frame.origin.x, newFrame.origin.y - frame.origin.y));
little.transform = t;

请注意,我只是输入了我的头脑中的代码来给你和想法。它需要测试和调试!

此外,如果您使用基于原始捏的缩放值而不是每次都重置它然后转换变换,则可以删除其中一些代码。