开发者

Scrolling with CALayer with different Z and speed values for parallax effect

I have created Layer for each of my background images in the following order:

-(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];
    }   

I can see the images one after the other and everything is ok, now I want to implement scrolling. You will notice that I created each layer with diffrent speed and Z value to basically create parallax efftect later on when rendering to the view. Before I am going with that path, are these values will lead me to where I want to go ? i.e will the Z value and the speed value of the layer will give me the effect that I want to see as sublayer of the view ?

Thanks ER


First off, let me just mention that your comments are mostly superfluous and make your code harder to read, not easier. Telling me /* Adding each layer to the layer of the view. */ when a line later you call a method named -addSublayer is simply noise. The name -addSublayer is descriptive enough. If people can't figure that out, they shouldn't be writing code. Furthermore, it won't help anyone who has to maintain your code in the future (including you). It will just feel like a lot more code to wade through than there really is.

Second, you have some unnecessary code inefficiencies. Here are a couple tips to help:

  1. Use fast enumeration. For loops are slow.

  2. There is no reason to create a data provider ref for loading your images. Just use -imageWithContentsOfFile instead

  3. Forget about using CAScrollLayer. There is no benefit to using it. UIScrollView will provide everything you need and is much simpler to implement. You simply set the contentSize property of the UIScrollView based on the extents of your content. This means you have to calculate it, but it's much simpler than trying to make CAScrollLayer work right. I believe that CAScrollLayer calculates the content area based on its sublayers so all you can do is add them as you are already doing. If scrolling is not working already, you have yet another reason to scrap it in favor of a UIScrollView.

Here is how I would simplify your code (except for swapping out the scroll layer for a scroll view. That's left as an exercise for the reader. ;-)

- (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];
}

Finally, in response to whether or not you can get a parallax effect, I think it will probably be pretty tough as Core Animation layers don't support the concept of a camera angle. The closest you're going to get, I think is to set the transform on each layer that you add to your hierarchy. You can set the z translation of the transform and enable perspective (by setting the .m34 field of the CATransfor3D structure). You can at that point just play around with the rotation of the containing layer and the x translation of the sublayers to try to get the effect you're looking for. The bottom line is that it won't just happen. You will have to play with the values a lot and might in the end be better off using OpenGL depending on how convincing your parallax needs to be.


If you want a classic parallax effect (ie, stuff in the back scrolls slower than stuff in the front), you can dispense with the CoreAnimation trickery and simply implement it yourself.

Just adjust the positions of your layers or views in response to scrolling, each frame. You can do this either as the UIScrollView delegate or by overriding, IIRC, -setBounds: or -layoutSubviews on the scrollview to do your own layout.

The basic idea is that for things "behind" the main plane, you can shift them downwards as you scroll to achieve the illusion that they're staying where they are, but are just further back in Z.

So, subtract a certain k * Y from your position values:

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

Where you pick k in [0,1) depending on how much effect you want. You could also define this in terms of Z or a ratio or whatever math you like.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜