【问题标题】:CATransformLayer and 3D rotation, venetian store or accordion like, keeping tiles adjacent?CATransformLayer 和 3D 旋转、威尼斯商店或手风琴之类的,保持瓷砖相邻?
【发布时间】:2014-05-26 05:07:00
【问题描述】:

我有一组垂直排列的瓷砖。它们旨在围绕 X 轴旋转。想想手风琴。我希望每个图块 n+1 始终挂在图块 n 上。

在最后两个屏幕截图中,青色图块应该附加到黄色图块上。它不是。 我不理解为什么。更不用说,为什么当我旋转第 0 行时,我会旋转所有接下来的 5 个图块(这是我想要的),但是当我想通过向另一个方向旋转从稍后的图块开始“纠正”时,我最终会在第三和第四块瓷砖。

作为参考,设置如下:

 CGRect  tileRect  = (CGRect)  {CGPointZero, {self.bounds.size.width, 30.0f}} ;
 CGRect  pageRect  = tileRect ;    pageRect.size.height *= 3 ;
 CGPoint baseCenter= (CGPoint) {self.bounds.size.width / 2.0f, 0} ;

 CGPoint anchorMidTop=   (CGPoint) {0.5f, 0.0f} ;
 CGPoint anchorTopLeft=  (CGPoint) {0.0f, 0.0f} ;

 CGPoint positionNW  =   (CGPoint) {0.0f, 0.0f} ;

 CALayer * (^setupLayerGeometry)(CALayer *, CGRect, CGPoint, CGPoint) =
 ^(CALayer * layer, CGRect b, CGPoint a, CGPoint p) {
     layer.bounds = b ;
     layer.anchorPoint = a ;
     layer.position = p ;
     return layer ;
 } ;

 CALayer * (^setupColor)(CALayer *, UIColor *) = ^(CALayer * layer, UIColor * color) {
     layer.backgroundColor = color.CGColor ;
     layer.opacity = 0.850f ;
     return layer ;
 } ;

 CALayer * (^stdLayer)(UIColor *, CGPoint, CGPoint) =
 ^CALayer * (UIColor * color, CGPoint anchor, CGPoint pos) {
     return setupLayerGeometry(
         setupColor([CALayer layer], color)
         ,   tileRect
         ,   anchor
         ,   pos) ;
 } ; 

 CATransformLayer * (^transformLayer)(CGRect, CGPoint, CGPoint) =
 ^CATransformLayer * (CGRect bounds, CGPoint anchor, CGPoint pos) {
     return (CATransformLayer *) setupLayerGeometry([CATransformLayer layer]
     ,   bounds
     ,   anchor
     ,   pos) ;
 } ;

 self.baseLayer = transformLayer(tileRect,    anchorTopLeft, baseCenter) ;

 CATransform3D initialTransform = self.baseLayer.sublayerTransform ;
 initialTransform.m34 = 1.0f / -200.0f ;
 self.baseLayer.sublayerTransform = initialTransform ;
 [self.layer addSublayer:self.baseLayer] ;

 CALayer * (^wrap0) (CALayer *) = ^CALayer * (CALayer * layer) {
     CALayer * wrap = transformLayer(tileRect,    anchorTopLeft, positionNW) ;
     [wrap addSublayer:layer] ;
     return wrap ;
 } ;

 CALayer * (^wrap)(CALayer *) = wrap0 ;

现在我正在创建六个图块,就像普通的 CALayer 一样。

 CALayer * row0  = stdLayer([UIColor redColor],      anchorMidTop, (CGPoint) {0, 0}) ;
 CALayer * row1  = stdLayer([UIColor blueColor],     anchorMidTop, (CGPoint) {0, 30}) ;
 CALayer * row2  = stdLayer([UIColor yellowColor],   anchorMidTop, (CGPoint) {0, 60}) ;
 CALayer * row3  = stdLayer([UIColor cyanColor],     anchorMidTop, (CGPoint) {0, 90}) ;
 CALayer * row4  = stdLayer([UIColor purpleColor],   anchorMidTop, (CGPoint) {0, 120}) ;
 CALayer * row5  = stdLayer([UIColor magentaColor],  anchorMidTop, (CGPoint) {0, 150}) ;

现在,我将每个这样的图块包装到父 CATransformLayer 中,然后我将其添加为 previous 行的子层,目的是让每个 CATransformLayer 影响其每个子层。

 [self.baseLayer  addSublayer:wrap(row0)] ;
 [row0.superlayer addSublayer:wrap(row1)] ;
 [row1.superlayer addSublayer:wrap(row2)] ;
 [row2.superlayer addSublayer:wrap(row3)] ;
 [row3.superlayer addSublayer:wrap(row4)] ;
 [row4.superlayer addSublayer:wrap(row5)] ;

 CGFloat angle = M_PI / 10.0f ;

 row0.superlayer.sublayerTransform = CATransform3DMakeRotation(-angle, 1, 0, 0);

此时我明白了:

我以为我已经成功了,直到我将最后一行替换为:

 row3.superlayer.sublayerTransform = CATransform3DMakeRotation(-angle, 1, 0, 0);

这就是我得到的:

如果我将上面的行替换为:

 row0.superlayer.sublayerTransform = CATransform3DMakeRotation(-angle, 1, 0, 0);
 row3.superlayer.sublayerTransform = CATransform3DMakeRotation( angle, 1, 0, 0);

我明白了:

我有read and re-read Apple's documentation,关注这个:

锚点影响几何操作

几何相关 图层的操作相对于该图层的锚点发生, 您可以使用图层的 anchorPoint 属性访问它。这 锚点的影响在操纵 图层的位置或变换属性。 位置属性 始终相对于图层的锚点指定,并且任何 您应用于图层的转换相对于锚点发生 点也是。

(强调我的)

公平地说,我现在完全糊涂了。任何人都可以看到/解释我做错了什么?

如何排列这些图层,使我的图块始终从上到下相邻?

这是层层次结构的转储:

 <CATransformLayer> frame: {{100, 0}, {200, 30}} pos: {100, 0} anchor: {0, 0}
   <CATransformLayer> frame: {{0, 0}, {200, 30}} pos: {0, 0} anchor: {0, 0}
     <CALayer> frame: {{-100, 0}, {200, 30}} pos: {0, 0} anchor: {0.5, 0}
     <CATransformLayer> frame: {{0, 0}, {200, 30}} pos: {0, 0} anchor: {0, 0}
       <CALayer> frame: {{-100, 30}, {200, 30}} pos: {0, 30} anchor: {0.5, 0}
       <CATransformLayer> frame: {{0, 0}, {200, 30}} pos: {0, 0} anchor: {0, 0}
         <CALayer> frame: {{-100, 60}, {200, 30}} pos: {0, 60} anchor: {0.5, 0}
         <CATransformLayer> frame: {{0, 0}, {200, 30}} pos: {0, 0} anchor: {0, 0}
           <CALayer> frame: {{-100, 90}, {200, 30}} pos: {0, 90} anchor: {0.5, 0}
           <CATransformLayer> frame: {{0, 0}, {200, 30}} pos: {0, 0} anchor: {0, 0}
             <CALayer> frame: {{-100, 120}, {200, 30}} pos: {0, 120} anchor: {0.5, 
             <CATransformLayer> frame: {{0, 0}, {200, 30}} pos: {0, 0} anchor: {0, 
               <CALayer> frame: {{-100, 150}, {200, 30}} pos: {0, 150} anchor: {0.5, 0}

【问题讨论】:

    标签: calayer catransformlayer


    【解决方案1】:

    我明白了。终于!

    代码如下:

    - (void) reloadData {
        for (CALayer * layer in [self.baseLayer.sublayers copy]) {
            [layer removeFromSuperlayer] ;
        }
    
        CGRect  tileRect  = (CGRect)  {CGPointZero, {self.bounds.size.width, 30.0f}} ;
        CGFloat halfWidth = self.bounds.size.width / 2.0f ;
    

    辅助块:

        CALayer * (^setupLayerGeometry)(CALayer *, CGRect, CGPoint, CGPoint, NSString *) =
        ^(CALayer * layer, CGRect b, CGPoint a, CGPoint p, NSString * n) {
            layer.bounds = b ;
            layer.anchorPoint = a ;
            layer.position = p ;
            layer.name = n ;
            return layer ;
        } ;
    
        CALayer * (^setupColor)(CALayer *, UIColor *) = ^(CALayer * layer, UIColor * color) {
            layer.backgroundColor = color.CGColor ;
            layer.opacity = 0.850f ;
            return layer ;
        } ;
    
        CALayer * (^stdLayer)(UIColor *, CGPoint, CGPoint, NSString *) =
        ^CALayer * (UIColor * color, CGPoint anchor, CGPoint pos, NSString * n) {
            return setupLayerGeometry(
                setupColor([CALayer layer], color)
            ,   tileRect
            ,   anchor
            ,   pos
            ,   n) ;
        } ;
    
        CATransformLayer * (^transformLayer)(CGRect, CGPoint, CGPoint, NSString *) =
        ^CATransformLayer * (CGRect bounds, CGPoint anchor, CGPoint pos, NSString * n) {
            return (CATransformLayer *) setupLayerGeometry(
                [CATransformLayer layer]
                ,   bounds
                ,   anchor
                ,   pos
                ,   n) ;
        } ;
    

    现在对于作为根 CATransformLayer 的 baseLayer

    #define ANC(x,y)    (CGPoint) {x, y}
    #define POS(x,y)    (CGPoint) {x, y}
    
        [self.baseLayer removeFromSuperlayer] ;
        self.baseLayer = transformLayer(tileRect,    ANC(0, 0), POS(halfWidth, 0), @"baseLayer") ;
    

    CATransformLayer 为根创建每一行,该根也充当下一行的超级层。

        CALayer * row0  = stdLayer([UIColor redColor],      ANC(0.0, 0.0), POS(-halfWidth, 0), @"row0") ;
        CATransformLayer * trn0 = (CATransformLayer *) transformLayer(tileRect,    ANC(0, 0), POS(0, 0), @"trn0") ;
        [self.baseLayer addSublayer:trn0] ;
        [trn0 addSublayer:row0] ;
    
    
        CALayer * row1  = stdLayer([UIColor blueColor],      ANC(0.0, 0.0), POS(-halfWidth, 0), @"row1") ;
        CATransformLayer * trn1 = (CATransformLayer *) transformLayer(tileRect,    ANC(0, 0), POS(0, 30), @"trn1") ;
        [trn1 addSublayer:row1] ;
        [trn0 addSublayer:trn1] ;
    
        CALayer * row2  = stdLayer([UIColor yellowColor],      ANC(0.0, 0.0), POS(-halfWidth, 0), @"row2") ;
        CATransformLayer * trn2 = (CATransformLayer *) transformLayer(tileRect,    ANC(0, 0), POS(0, 30), @"trn2") ;
        [trn2 addSublayer:row2] ;
        [trn1 addSublayer:trn2] ;
    
        CALayer * row3  = stdLayer([UIColor cyanColor],      ANC(0.0, 0.0), POS(-halfWidth, 0), @"row3") ;
        CATransformLayer * trn3 = (CATransformLayer *) transformLayer(tileRect,    ANC(0, 0), POS(0, 30), @"trn3") ;
        [trn3 addSublayer:row3] ;
        [trn2 addSublayer:trn3] ;
    
        CALayer * row4  = stdLayer([UIColor purpleColor],      ANC(0.0, 0.0), POS(-halfWidth, 0), @"row4") ;
        CATransformLayer * trn4 = (CATransformLayer *) transformLayer(tileRect,    ANC(0, 0), POS(0, 30), @"trn4") ;
        [trn4 addSublayer:row4] ;
        [trn3 addSublayer:trn4] ;
    
        CALayer * row5  = stdLayer([UIColor magentaColor],      ANC(0.0, 0.0), POS(-halfWidth, 0), @"row5") ;
        CATransformLayer * trn5 = (CATransformLayer *) transformLayer(tileRect,    ANC(0, 0), POS(0, 30), @"trn5") ;
        [trn5 addSublayer:row5] ;
        [trn4 addSublayer:trn5] ;
    
        CALayer * row6  = stdLayer([UIColor lightGrayColor],      ANC(0.0, 0.0), POS(-halfWidth, 0), @"row6") ;
        CATransformLayer * trn6 = (CATransformLayer *) transformLayer(tileRect,    ANC(0, 0), POS(0, 30), @"trn6") ;
        [trn6 addSublayer:row6] ;
        [trn5 addSublayer:trn6] ;
    
        CALayer * row7  = stdLayer([UIColor darkGrayColor],      ANC(0.0, 0.0), POS(-halfWidth, 0), @"row7") ;
        CATransformLayer * trn7 = (CATransformLayer *) transformLayer(tileRect,    ANC(0, 0), POS(0, 30), @"trn7") ;
        [trn7 addSublayer:row7] ;
        [trn6 addSublayer:trn7] ;
    

    最后设置变换。由于每一行都是下一行的父行(感谢嵌入的CATransformLayer),因此所需的角度是相对于直接父行的,因此与显示特定图块的行号无关。

        CGFloat angle = M_PI / 10.0f ;
    
        trn0.sublayerTransform =  CATransform3DMakeRotation(1.0*angle, 1, 0, 0);
        trn1.sublayerTransform =  CATransform3DMakeRotation(-1.0*angle, 1, 0, 0);
        trn2.sublayerTransform =  CATransform3DMakeRotation(-1.0*angle, 1, 0, 0);
        trn3.sublayerTransform =  CATransform3DMakeRotation(1.0*angle, 1, 0, 0);
        trn4.sublayerTransform =  CATransform3DMakeRotation(1.0*angle, 1, 0, 0);
        trn5.sublayerTransform =  CATransform3DMakeRotation(-1.0*angle, 1, 0, 0);
        trn6.sublayerTransform =  CATransform3DMakeRotation(-1.0*angle, 1, 0, 0);
        trn7.sublayerTransform =  CATransform3DMakeRotation(2.0*angle, 1, 0, 0);
    
        CATransform3D initialTransform = self.baseLayer.sublayerTransform ;
        initialTransform.m34 = 1.0f / -200.0f ;
        self.baseLayer.sublayerTransform = initialTransform ;
    
        [self.layer addSublayer:self.baseLayer] ;
    
    #undef ANC
    #undef POS
    
    }
    

    现在我只需要去掉那些愚蠢的颜色,消除边缘的锯齿,并提供一些阴影渐变层,然后观察那个让我烦恼的透视图(最后一行“灰色”太高了)使用 m34 和/或进行更多调整baseLayer 中心 [anchorPoint/position]。

    将角度和系数替换为:

        CGFloat angle = M_PI / 3.0f ;
    
        trn0.sublayerTransform =  CATransform3DMakeRotation(-1.0*angle, 1, 0, 0);
        trn1.sublayerTransform =  CATransform3DMakeRotation(2.0*angle, 1, 0, 0);
        trn2.sublayerTransform =  CATransform3DMakeRotation(-2.0*angle, 1, 0, 0);
        trn3.sublayerTransform =  CATransform3DMakeRotation(2.0*angle, 1, 0, 0);
        trn4.sublayerTransform =  CATransform3DMakeRotation(-2.0*angle, 1, 0, 0);
        trn5.sublayerTransform =  CATransform3DMakeRotation(2.0*angle, 1, 0, 0);
        trn6.sublayerTransform =  CATransform3DMakeRotation(-2.0*angle, 1, 0, 0);
        trn7.sublayerTransform =  CATransform3DMakeRotation(2.0*angle, 1, 0, 0);
    

    以及对以下方面的看法:

        initialTransform.m34 = 1.0f / -400.0f ;
    

    我们现在得到:

    【讨论】:

      猜你喜欢
      • 2020-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-18
      • 1970-01-01
      • 1970-01-01
      • 2021-05-17
      相关资源
      最近更新 更多