使用具有不同Z和速度值的CALayer滚动以获得视差效果

时间:2011-02-07 20:26:02

标签: iphone uiscrollview core-animation calayer

我已按以下顺序为每个背景图像创建了图层:

-(void)SetView
{

        /* Getting the plist path to load */

       NSString *plistPath = [[NSBundle mainBundle] pathForResource:plistName ofType:@"plist"];

        /* Printing the plistPath value */

        NSLog(@"plistPath:%@",plistPath);

        /* loading the image names to an array */

        NSArray *array = [[NSArray alloc] initWithContentsOfFile:plistPath];

        /* Creating loop to create each background image as a layer */

        for (int i=0; i< [array count]; i++) 
        {
            /* Set the image name of each index*/

            NSString *imageName = [array objectAtIndex:i];

            /* Printing the imageName value */

            NSLog(@"imageName: %@",imageName);


            /* allocate new CAScroll object */

            subLayer = [[CAScrollLayer alloc] init];


            /* Define const char as the image name.*/

            const char *fileName = [[[NSBundle mainBundle] pathForResource:imageName ofType:@"png"] UTF8String];

            /* Printing the fileName value */

             NSLog(@"fileName: %s",fileName);

            /* Setting the data reference as the image file name */

            CGDataProviderRef dataRef = CGDataProviderCreateWithFilename(fileName);

            /* Printing the dataRef value */

            NSLog(@"dataRef: %@",dataRef);

            /* Creating image reference supplying the image name as data source */

                CGImageRef image = CGImageCreateWithPNGDataProvider
                (dataRef, NULL, 
                 NO, kCGRenderingIntentDefault);


            /* Define the contents of the layer */

            subLayer.contents = (id)[UIImage imageWithCGImage:image scale:2.0 orientation: UIImageOrientationRight].CGImage;             

            /* Printing the contenet of the subLayer */

            NSLog(@" Print the content %@",subLayer.contents);


            /* Define the frame of the layer */
            subLayer.frame = CGRectMake(0, 0,480,320);

            /* The rate of the layer. Used to scale parent time to local time, e.g.
             * if rate is 2, local time progresses twice as fast as parent time.
             * Defaults to 1. */

            subLayer.speed = (float)i;

            /* The Z component of the layer's position in its superlayer. Defaults
             * to zero. Animatable. */

            subLayer.zPosition = (float)i;

            /* Adding each layer to the layer of the view. */

                [self.layer addSublayer:subLayer];



        }
        /* Release the array after adding all layers */

        [array release];
    }   

我可以一个接一个地看到图像,一切正常,现在我想实现滚动。 您会注意到我创建了具有不同速度和Z值的每个图层,以便在渲染到视图时基本上创建视差效果。 在我走这条路之前,这些价值观会带我到我想去的地方吗? 也就是说,Z值和图层的速度值会给我带来的效果,我想看到它作为视图的子层?

由于 ER

2 个答案:

答案 0 :(得分:7)

首先,我要提一下,你的评论大多是多余的,让你的代码更难阅读,而不是更容易。稍后您调用名为/* Adding each layer to the layer of the view. */的方法时,告诉我-addSublayer只是噪音。名称-addSublayer足够具有描述性。如果人们无法弄明白,他们就不应该编写代码。此外,它对将来必须维护您的代码(包括您)的任何人都无济于事。它只会感觉需要更多的代码才能实现。

其次,你有一些不必要的代码效率低下。以下是一些帮助提示:

  1. 使用快速枚举。因为循环很慢。

  2. 没有理由为加载图片创建数据提供者引用。只需使用-imageWithContentsOfFile代替

  3. 忘记使用CAScrollLayer。使用它没有任何好处。 UIScrollView将提供您所需的一切,并且simpler to implement很多。您只需根据内容的范围设置UIScrollView的contentSize属性。这意味着您必须计算它,但它比尝试使CAScrollLayer正常工作简单得多。我相信CAScrollLayer会根据其子层计算内容区域,所以你所能做的就是按照你已经做的那样添加它们。如果滚动功能尚未完成,您还有另一个理由要废弃它以支持UIScrollView。

  4. 以下是我如何简化代码(除了为滚动视图更换滚动图层。这是留给读者的练习。) - )

    - (void)SetView
    {      
      NSString *plistPath = [[NSBundle mainBundle] 
                                  pathForResource:plistName ofType:@"plist"];
    
      NSArray *array = [[NSArray alloc] initWithContentsOfFile:plistPath];
    
      int i = 0;
    
      for (NSString *imageName in array) // fast enumeration
      {
        subLayer = [[CAScrollLayer alloc] init];
    
        NSString *fileName = [[NSBundle mainBundle] 
                                 pathForResource:imageName ofType:@"png"];
    
        UIImage *image = [UIImage imageWithContentsOfFile:filename];
    
        subLayer.contents = (id)[UIImage 
                             imageWithCGImage:[image CGImage] 
                                        scale:2.0 
                       orientation:UIImageOrientationRight].CGImage;             
    
        subLayer.frame = CGRectMake(0, 0,480,320);
        subLayer.speed = (float)i;
        subLayer.zPosition = (float)i;
    
        [self.layer addSublayer:subLayer];
    
        i++;
      }
      [array release];
    }
    

    最后,为了回应你是否能获得视差效果,我认为它可能会非常艰难,因为Core Animation图层不支持摄像机角度的概念。您最接近的是,我认为是在您添加到层次结构的每个图层上设置变换。您可以设置转换的z转换并启用透视图(通过设置CATransfor3D结构的.m34字段)。你可以在这一点上玩围绕包含层的旋转和子层的x平移,以试图获得你正在寻找的效果。最重要的是它不会发生。您将不得不大量使用这些值,最终可能最好使用OpenGL,具体取决于您的视差需要多么令人信服。

答案 1 :(得分:1)

如果你想要一个经典的视差效果(即背面的东西比前面的东西慢,那么你可以省去CoreAnimation技巧并自己实现它。

只需调整图层或视图的位置以响应每个帧的滚动。您既可以将其作为UIScrollView委托,也可以通过覆盖滚动视图上的IIRC,-setBounds:或-layoutSubviews来执行此操作。

基本理念是,对于事物&#34;背后&#34;在主飞机上,当你滚动时你可以将它们向下移动,以实现它们停留在原地的错觉,但只是回到Z.

因此,从您的头寸值中减去某个k * Y:

layer.position = (CGPoint){logicalPosition.x, logicalPosition.y - k * contentOffset.y}

根据您想要的效果,在[0,1]中选择k。你也可以用Z或比率或你喜欢的任何数学来定义它。