Прокрутка с помощью CALayer с различными значениями Z и скорости для эффекта параллакса - PullRequest
1 голос
/ 07 февраля 2011

Я создал слой для каждого из моих фоновых изображений в следующем порядке:

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

7 голосов
/ 09 февраля 2011

Прежде всего, позвольте мне упомянуть, что ваши комментарии в основном излишни и делают ваш код труднее читать, а не легче.Сказать мне /* Adding each layer to the layer of the view. */, когда через строку вы вызываете метод с именем -addSublayer, это просто шум.Имя -addSublayer достаточно наглядно.Если люди не могут понять это, они не должны писать код.Кроме того, это не поможет никому, кто должен поддерживать ваш код в будущем (включая вас).Просто будет гораздо больше кода, чем нужно на самом деле.

Во-вторых, у вас есть некоторые ненужные недостатки кода.Вот несколько полезных советов:

  1. Используйте быстрое перечисление.Поскольку петли медленные.

  2. Нет причин создавать ссылку на провайдера данных для загрузки ваших изображений.Просто используйте -imageWithContentsOfFile вместо

  3. Забудьте об использовании CAScrollLayer.Нет пользы от его использования.UIScrollView предоставит все, что вам нужно, и намного проще для реализации .Вы просто устанавливаете свойство contentSize UIScrollView на основе экстентов вашего контента.Это означает, что вы должны рассчитать его, но это гораздо проще, чем пытаться заставить CAScrollLayer работать правильно.Я считаю, что CAScrollLayer вычисляет область содержимого на основе его подслоев, поэтому все, что вы можете сделать, это добавить их, как вы уже делаете.Если прокрутка уже не работает, у вас есть еще одна причина отказаться от нее в пользу UIScrollView.

Вот как я бы упростил ваш код (за исключением замены слоя прокрутки дляпредставление прокрутки. Это оставлено как упражнение для читателя.; -)

- (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Слои анимации не поддерживают концепцию угла камеры.Думаю, самое близкое, что вы получите, - это установить преобразование для каждого слоя, который вы добавляете в свою иерархию.Вы можете установить трансформацию z трансформации и включить перспективу (установив поле .m34 структуры CATransfor3D).В этот момент вы можете просто поиграть с вращением содержащего слоя и трансляцией x подслоев, чтобы получить нужный эффект.Суть в том, что этого не произойдет.Вам придется много играть со значениями, и в конечном итоге вам будет лучше использовать OpenGL в зависимости от того, насколько убедительным должен быть ваш параллакс.

1 голос
/ 11 ноября 2011

Если вам нужен классический эффект параллакса (т. Е. Материал на задней прокрутке медленнее, чем материал на передней панели), вы можете отказаться от трюка с CoreAnimation и просто реализовать его самостоятельно.

Просто отрегулируйте положение ваших слоев или представлений в ответ на прокрутку каждого кадра. Вы можете сделать это либо как делегат UIScrollView, либо переопределив IIRC, -setBounds: или -layoutSubviews в scrollview, чтобы создать свой собственный макет.

Основная идея заключается в том, что для вещей, находящихся "за" основным планом, вы можете сдвигать их вниз по мере прокрутки, чтобы создать иллюзию, что они остаются там, где они есть, но находятся чуть дальше в Z.

Итак, вычтите определенное k * Y из значений вашей позиции:

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

Где вы выбираете k в [0,1) в зависимости от того, какой эффект вы хотите. Вы также можете определить это с точки зрения Z или отношения или любой другой математики, которая вам нравится.

...