CALayer如何将点从其子层转换到本身,以及从本身转换到其子层?

3
假设我们有一个二维空间(为了简化情况),以及层S和层C,其中C是S的子层。转换过程必须影响C的边界、位置、变换、S的子层的变换和C的锚点。我的猜测如下:
CGAffineTransform transformToChild(CALayer *S, CALayer *C) {
    CGFloat txa = - C.bounds.origin.x - C.bounds.size.width * C.anchorPoint.x;
    CGFloat tya = - C.bounds.origin.y - C.bounds.size.height * C.anchorPoint.y;

    CGFloat txb = C.position.x;
    CGFloat tyb = C.position.y;

    CGAffineTransform sublayerTransform = CATransform3DGetAffineTransform(S.sublayerTransform);
    CGAffineTransform fromS = CGAffineTransformTranslate(sublayerTransform, txb, tyb);
    fromS = CGAffineTransformConcat(fromS, C.affineTransform);
    fromS = CGAffineTransformTranslate(fromS, txa, tya);

    return fromS;
}

但是当子图层的变换不是单位矩阵时(例如,在旋转到M_PI_2角度的情况下),这种方法就无法起作用。

完整的代码和图层如下:

CALayer *l1 = [CALayer new];
l1.frame = CGRectMake(-40, -40, 80, 80);
l1.bounds = CGRectMake(40, 40, 80, 80);
CALayer *l2 = [CALayer new];
l2.frame = CGRectMake(50, 40, 20, 20);
l2.bounds = CGRectMake(40, 40, 20, 20);
CGAffineTransform t2 = CGAffineTransformMakeRotation(M_PI / 2);
l2.affineTransform = t2;
[l1 addSublayer:l2];

CGAffineTransform toL2 = transformToChild(l1, l2);
CGPoint p = CGPointApplyAffineTransform(CGPointMake(70, 50), toL2);
NSLog(@"Custom Point %@", [NSValue valueWithCGPoint:p]);

p = [l1 convertPoint:CGPointMake(70, 50) toLayer:l2];
NSLog(@"CoreAnimation Point %@", [NSValue valueWithCGPoint:p]);

与系统结果的比较:

Custom Point NSPoint: {-50, 80}
CoreAnimation Point NSPoint: {50, 40}

1
这个关于帧的解释回答了你的问题吗? - David Rönnqvist
1
谢谢,David。是的,根据那篇文章,我发现我必须对子层的变换进行点变换,而不将其连接到任何翻译中。并将偏移应用于点坐标。我很快会添加更具体的解释作为答案。 - Eugene Dudnyk
2个回答

1

0

所以,我发现了一种在子层坐标空间中进行点转换的方法,它可以正确地处理子层的非恒等变换。超级图层的子层变换没有在这里涵盖,但我认为扩展这些函数以支持它不会很难。

CGPoint pointToChild(CALayer *C, CGPoint p) {

    CGFloat txa = - C.bounds.origin.x - C.bounds.size.width * C.anchorPoint.x;
    CGFloat tya = - C.bounds.origin.y - C.bounds.size.height * C.anchorPoint.y;

    CGFloat txb = C.position.x;
    CGFloat tyb = C.position.y;

    p.x -= txb;
    p.y -= tyb;

    p = CGPointApplyAffineTransform(p, CGAffineTransformInvert(C.affineTransform));

    if (C.isGeometryFlipped) {
        CGAffineTransform flip = CGAffineTransformMakeScale(1.0f, -1.0f);
        flip = CGAffineTransformTranslate(flip, 0, C.bounds.size.height * (2.0f * C.anchorPoint.y - 1.0f));
        p = CGPointApplyAffineTransform(p, CGAffineTransformInvert(flip));
    }

    p.x -= txa;
    p.y -= tya;

    return p;
}

CGPoint pointFromChild(CALayer *C, CGPoint p) {

    CGFloat txb = - C.bounds.origin.x - C.bounds.size.width * C.anchorPoint.x;
    CGFloat tyb = - C.bounds.origin.y - C.bounds.size.height * C.anchorPoint.y;

    CGFloat txa = C.position.x;
    CGFloat tya = C.position.y;

    p.x += txb;
    p.y += tyb;

    if (C.isGeometryFlipped) {
        CGAffineTransform flip = CGAffineTransformMakeScale(1.0f, -1.0f);
        flip = CGAffineTransformTranslate(flip, 0, C.bounds.size.height * (2.0f * C.anchorPoint.y - 1.0f));
        p = CGPointApplyAffineTransform(p, flip);   
    }

    p = CGPointApplyAffineTransform(p, C.affineTransform);

    p.x += txa;
    p.y += tya;

    return p;
}

那么,view.layer.sublayerTransform和view.layer.transform呢? - hfossli
/* 返回由 't' 表示的仿射变换。如果 't' 不能被精确地表示为仿射变换,则返回值未定义。 */ CATransform3DGetAffineTransform - hfossli
问题是关于2D空间的。我认为UIView始终可以很好地使用图层的affineTransform属性(如果您没有直接修改图层的transform属性)。 - Eugene Dudnyk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接