【问题标题】:Same CGAffineTransform different anchor相同的 CGAffineTransform 不同的锚点
【发布时间】:2012-01-04 17:46:55
【问题描述】:

我有 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];
}

但这不起作用,小视图不断跳来跳去,发疯了。

编辑:更多信息。

好的,这是图表:

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

行:[self adjustAnchorPointForGestureRecognizer:gestureRecognizer];将大视图锚点更改为捏合手势的中心。这行得通。

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

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

【问题讨论】:

  • 您能否添加一些图表来显示视图在紧要关头之前的外观,然后它们应该如何外观?我无法从描述中得到你想要的效果。
  • 进一步编辑,我在下面的回复的本质仍然有效。根据比例因子和大视图的位置(可以从框架中获取)计算小视图的新位置,并创建将其放置在那里的变换。

标签: objective-c cgaffinetransform


【解决方案1】:

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

- (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 会不同步。所以我不直接将转换应用到 UIView,我将它们与 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;
        }

    }
}

【讨论】:

    【解决方案2】:

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

    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;
    

    请注意,我刚刚在脑海中输入了代码,以便为您提供建议。它需要测试和调试!

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

    提姆

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-24
      • 2019-10-30
      • 2023-01-11
      • 2022-11-26
      • 2012-02-04
      • 2017-09-10
      相关资源
      最近更新 更多