Параллакс-эффект с подзаголовками UIScrollView

Я пытаюсь создать эффект Parallax на UIView внутри UIScrollView. Эффект, похоже, работает, но не так хорошо.

  • Сначала я добавлю два поднабора UIView в UIScrollView и настрою содержимое UIScrollViews contentSize.
  • Подводя итоги и создайте contentSize из {320, 1000}.
  • Затем я выполнил следующее в scrollViewDidScroll:

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView
    {
        CGFloat offsetY = scrollView.contentOffset.y;
    
        CGFloat percentage = offsetY / scrollView.contentSize.height;
    
        NSLog(@"percent = %f", percentage);
    
        if (offsetY < 0) {
    
            firstView.center = CGPointMake(firstView.center.x, firstView.center.y - percentage * 10);
    
        } else if (offsetY > 0){
    
            firstView.center = CGPointMake(firstView.center.x, firstView.center.y + percentage * 10);
    
        }
    }
    

Эти строки кода создают эффект параллакса, но по мере продолжения прокрутки представление не возвращается к исходной позиции, если я просматриваю исходную начальную позицию.

Я попытался манипулировать слоями и рамками представлений, все с одинаковыми результатами.

Любая помощь будет высоко оценена.

Ответ 1

Проблема заключается в том, что вы основываете свою вторичную прокрутку на соотношении смещения к размеру, а не только на текущем смещении. Поэтому, когда вы увеличиваете с смещения от 99 до 100 (из 100), ваш вторичный свиток увеличивается на 10, но когда вы возвращаетесь вниз до 99, ваш вторичный свиток уменьшается только на 9,9 и, следовательно, больше не находится на том же месте, что и это был последний раз, когда вы были в 99. Нелинейная прокрутка возможна, но не так, как вы это делаете.

Возможный более простой способ справиться с этим - создать второе прокручивание и поместить его ниже своего фактического прокрутки. Сделайте это не сложно (setUserInteractionEnabled:false) и измените его contentOffset во время основного делегата прокрутки, вместо того, чтобы вручную перемещать UIImageView.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    [scrollView2 setContentOffset:CGPointMake(scrollView.contentOffset.x,scrollView.contentOffset.y * someScalingFactor) animated:NO];
}

Но не устанавливайте делегат для scrollView2, иначе вы можете получить вызов метода кругового делегата, который не закончится хорошо для вас.

Ответ 2

Масштабный коэффициент является ключевым элементом...

... позвольте мне предложить расчет 1:1:

Предполагая, что 2 UIScrollView, один на переднем плане и сзади в задней части, при условии, что передний план управления сзади, и, если предположить, что полная ширина на переднем плане соответствует полной ширине в фоновом режиме, тогда вам необходимо применить fore , а не fore offset.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let foreSpan = foreScrolView.bounds.width - foreScrolView.contentSize.width
    let foreRatio = scrollView.contentOffset.x / foreSpan
    let rearSpan = rearScrollView.bounds.width - rearScrollView.contentSize.width
    rearScrollView.setContentOffset(
        CGPoint(x: foreRatio * rearSpan, y: 0),
        animated: false)
}

Конечный эффект

Параллакс-эффект

Два скроллера, передние и задние, содержат UIImageView, отображаемые по всей ширине:

let foreImg = UIImageView.init(image: UIImage(named: "fore"))
foreImg.frame = CGRect(x: 0, y: 0,
                       width: foreImg.frame.width,
                       height: foreScrolView.bounds.height)
foreScrolView.contentSize = foreImg.frame.size
foreScrolView.addSubview(foreImg)

let rearImg = UIImageView.init(image: UIImage(named: "rear"))
rearImg.frame = CGRect(x: 0, y: 0,
                       width: rearImg.frame.width,
                       height: rearScrollView.bounds.height)
rearScrollView.contentSize = rearImg.frame.size
rearScrollView.addSubview(rearImg)

Это позволит прокручивать оба изображения с другой скоростью, охватывая каждое изображение полностью от края к краю.


► Найти это решение на GitHub и дополнительные сведения о Быстрые рецепты.