Parallax effect with UIScrollView subviews

后端 未结 2 1996
北恋
北恋 2020-12-14 04:04

I\'m trying to create a Parallax effect on a UIView inside a UIScrollView. The effect seems to work, but not so well.

  1. First i add two UIView sub-views to a UI
相关标签:
2条回答
  • 2020-12-14 04:39

    The problem you have is that you are basing your secondary scrolling on a ratio of offset to size, not just on the current offset. So when you increase from an offset of 99 to 100 (out of say 100) your secondary scroll increases by 10, but when you go back down to 99 your secondary scroll only decreases by 9.9, and is thereby no longer in the same spot as it was last time you were at 99. Non-linear scrolling is possible, but not the way you are doing it.

    A possible easier way to deal with this is to create a second scrollview and place it below your actual scrollview. Make it non intractable (setUserInteractionEnabled:false) and modify it's contentOffset during the main scrolling delegate instead of trying to move a UIImageView manually.

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

    But make sure not to set a delegate for the scrollView2, otherwise you may get a circular delegate method call that will not end well for you.

    0 讨论(0)
  • 2020-12-14 04:57

    Scaling Factor being the key element...

    ...let me offer a 1:1 calculation:

    Assuming 2 UIScrollView, one in the foreground and on in the rear, assuming the foreground controls the rear, and further assuming that a full width in the foreground corresponds to a full width in the background, you then need to apply the fore ratio, not the 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)
    }
    

    Final effect

    The two scrollers, fore and rear, each contain a UIImageView displayed at its full width:

    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)
    

    This will scroll both images at a different speed, covering each image in full from edge to edge.


    ► Find this solution on GitHub and additional details on Swift Recipes.

    0 讨论(0)
提交回复
热议问题