user4170419
user4170419

Reputation:

Creating infinite background scroll right to left

I am trying to create an animation to create an illusion of moving object. So the object will stay at the same position but the background image view which is wider than screen width will move infinitely. The code I have doesn't work very smooth.

    let backgroundView = UIView()
    backgroundView.backgroundColor = UIColor.blueColor()
    backgroundView.frame = CGRect(x: 0, y: 120, width: 50, height: 50)
    self.view.addSubview(backgroundView)
    let options = UIViewAnimationOptions.Repeat | UIViewAnimationOptions.CurveLinear

    UIView.animateWithDuration(2.0, delay: 0.0, options: options, animations: {
        backgroundView.frame = CGRect(x: 420, y: 120, width: 50, height: 50)
        }, completion: nil) 

Upvotes: 3

Views: 4110

Answers (2)

Ankit Goyal
Ankit Goyal

Reputation: 3049

For Swift 5.0+, use the below function.

func animateBackground()
{
    let backgroundImage = UIImage(named:"bgImage")!

    // UIImageView 1
    let backgroundImageView1 = UIImageView(image: backgroundImage)
    backgroundImageView1.frame = CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width: self.view.frame.size.width, height: self.view.frame.size.height)
    backgroundImageView1.contentMode = .scaleAspectFit
    self.view.addSubview(backgroundImageView1)

    // UIImageView 2
    let backgroundImageView2 = UIImageView(image: backgroundImage)
    backgroundImageView2.frame = CGRect(x: self.view.frame.size.width, y: self.view.frame.origin.y, width: self.view.frame.size.width, height: self.view.frame.height)
    backgroundImageView2.contentMode = .scaleAspectFit
    self.view.addSubview(backgroundImageView2)

    // Animate background
    UIView.animate(withDuration: 6.0, delay: 0.0, options: [.repeat, .curveLinear], animations: {
        backgroundImageView1.frame = backgroundImageView1.frame.offsetBy(dx: -1 * backgroundImageView1.frame.size.width, dy: 0.0)
        backgroundImageView2.frame = backgroundImageView2.frame.offsetBy(dx: -1 * backgroundImageView2.frame.size.width, dy: 0.0)
        }, completion: nil)
}

Upvotes: 2

Daniel Storm
Daniel Storm

Reputation: 18878

Updated answer:

To animate a background image like you've mentioned in your comment, one way would be to create a seamless pattern for your background image and move it across the screen. For example, Move image1 across screen, follow it with image2, move image1 back to original position, move image2 back to original position, repeat. There's probably an easier way to do this depending on what you're actually going to be using this for, but this is just one example. I've made a simple background pattern for this example, feel free to use it.

func animateBackground() {
    let animationOptions = UIViewAnimationOptions.Repeat | UIViewAnimationOptions.CurveLinear
    let backgroundImage = UIImage(named:"backgroundPattern.jpg")!
    var amountToKeepImageSquare = backgroundImage.size.height - self.view.frame.size.height

    // UIImageView 1
    var backgroundImageView1 = UIImageView(image: backgroundImage)
    backgroundImageView1.frame = CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width: backgroundImage.size.width - amountToKeepImageSquare, height: self.view.frame.size.height)
    self.view.addSubview(backgroundImageView1)

    // UIImageView 2
    var backgroundImageView2 = UIImageView(image: backgroundImage)
    backgroundImageView2.frame = CGRect(x: backgroundImageView1.frame.size.width, y: self.view.frame.origin.y, width: backgroundImage.size.width - amountToKeepImageSquare, height: self.view.frame.height)
    self.view.addSubview(backgroundImageView2)

    // Animate background
    UIView.animateWithDuration(6.0, delay: 0.0, options: animationOptions, animations: {
        backgroundImageView1.frame = CGRectOffset(backgroundImageView1.frame, -1 * backgroundImageView1.frame.size.width, 0.0)
        backgroundImageView2.frame = CGRectOffset(backgroundImageView2.frame, -1 * backgroundImageView2.frame.size.width, 0.0)
        }, completion: nil)

    // Have something in the foreground look like its moving
    var square = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
    square.frame.origin = CGPoint(x: self.view.frame.origin.x + 25, y: self.view.frame.size.height - 75)
    square.backgroundColor = UIColor.darkGrayColor()
    self.view.addSubview(square)

    // Animate foreground
    UIView.animateWithDuration(0.5, delay: 0, options: animationOptions, animations: {
        square.transform = CGAffineTransformMakeRotation(33)
        }, completion: nil)
}

You'll end up with an animation like this:

animatedBackground

Original answer:

I'm not entirely sure what you're trying to achieve, but from what I can gather you'd like your view to not jump back to its starting position when it repeats each animation. You can achieve this by setting your UIView's starting point off the left side of the view and its ending point off the right side of the view.

func animateSquare() {
    // Create our square with size of 50x50
    var square = UIView(frame: CGRect(x: 0, y: self.view.frame.height / 2, width: 50, height: 50))
    // Set its origin just off the left of the screen so it is not visible
    square.frame.origin = CGPoint(x: 0 - square.frame.size.width, y: self.view.frame.height / 2)
    square.backgroundColor = UIColor.blackColor()
    self.view.addSubview(square)

    // Setup animation and repeat
    let animationOptions = UIViewAnimationOptions.Repeat | UIViewAnimationOptions.CurveLinear
    UIView.animateWithDuration(2.0, delay: 0, options: animationOptions, animations: {
        // Offset our square's frame by the width of the view + the width of the square
        // This way it moves off the screen to the right completely
        square.frame = CGRectOffset(square.frame, self.view.frame.width + square.frame.width, 0.0)
        }, completion: nil)
}

You'll end up with an animation like this:

animatedSquare

Upvotes: 12

Related Questions