iOS — Infinite Marquee Animation with SwiftUI

Let’s explore how to apply the marquee animation effect on any view!
Aug 15 2022 · 4 min read

Background

Static is boring nowadays, especially in Mobile designs. Designers are looking for more and more creative ways to attract users’ attention.


At the same time, platforms are providing really good support for the easier implementation of crazy animations!

Last week, we also received one such requirement from our designer team. The app we were working on is Nolonely — Build healthy habits, available on both android and iOS platforms.

Here are our previous and new designs.

Previous design.png
Previous Design
New Design

 As you can see, the right is much more engaging and eye catchy. AppStore app also has similar animation.

Today we will explore how we can implement infinite scrolling animations that look seamless.

Outline

We will not implement exact same UI here as it will be very time-consuming and also unrelated to the animation we are implementing.
Instead, we will create a simple app with 4 colored blocks that keep moving.

Later, we will also explore how we can create a common component InfiniteScrollerthat can be used to apply infinite scrolling animation to any view.

I have divided this post into 3 parts, feel free to jump around!

  1. Create basic views
  2. Apply infinite scroll animation
  3. Create InfiniteScroller component

If you are in hurry and just need to apply the animation in your project, feel free to just copy InfiniteScroller in your app and you are ready to go.

Alright, let’s begin!

We are what we repeatedly do. Excellence, then, is not an act, but a habit. Try out Justly and start building your habits today!

1. Create Basic Views

Let’s start by adding a ColorAnimationView that has 4 colored blocks with a size of screenWidth/4.


struct ColorAnimationView: View {
    var body: some View {
        GeometryReader { geometry in
            let size = geometry.size.width / 4
            HStack(spacing: 0) {
                ColorView(size: size, color: Color.green)
                ColorView(size: size, color: Color.white)
                ColorView(size: size, color: Color.pink)
                ColorView(size: size, color: Color.cyan)
            }
            .padding(.vertical, 100)
        }
    }
}

struct ColorView: View {
    var size: CGFloat
    var color: Color
    
    var body: some View {
        VStack {
            VStack{}.frame(width: size, height: size, alignment: .center)
        }
        .background(color)
    }
}

Nothing fancy here, we have just added a ColorView that accepts size and color and then we have used 4 instances of that view in ColorAnimationView .

Run the app and you will see the following UI.

1_kDMltlBkBQTxN8IC8PmA5Q.png

2. Apply Infinite Scroll Animation

Alright, now it’s time to animate those color blocks.

The trick to applying infinite scrolling animation is to add a duplicate color block at the end and then later when an exact 1 page is scrolled, that is equal to the total width of 4 colored blocks, set scroll offset to 0 again.

It’s easier to explain with code rather than words, let’s add a code to animate those blocks!


struct ColorAnimationView: View {
    
    @State
    var xOffset: CGFloat = 0
    
    var body: some View {
        GeometryReader { geometry in
            let size = geometry.size.width / 4
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 0) {
                    ColorView(size: size, color: Color.green)
                    ColorView(size: size, color: Color.white)
                    ColorView(size: size, color: Color.pink)
                    ColorView(size: size, color: Color.cyan)
                    
                    // Add Dupliate color blocks to mimic infinie animation
                    ColorView(size: size, color: Color.green)
                    ColorView(size: size, color: Color.white)
                    ColorView(size: size, color: Color.pink)
                    ColorView(size: size, color: Color.cyan)
                }
                .padding(.vertical, 100)
                .offset(x: xOffset, y: 0)
            }.disabled(true)
            .onAppear {
                withAnimation(.linear(duration: 3).repeatForever(autoreverses: false)) {
                    xOffset = -size * 4
                }
            }
        }
    }
}

Let’s explore changes

  1. We have added a xOffset variable for horizontal animation. We will animate its value from 0 to -size * 4 and will repeat the animation forever. That means when 4 blocks are scrolled off the screen, the animation will start from 0 offset again but users will not notice it because the exact frame of duplicate views will be visible at that time.
  2. Wrapped the content inside a ScrollView and set it to disabled to make sure it can not be scrolled manually with gestures.
  3. Now to the main part, we have added duplicate content of we already had, to make the animation look infinite. The trick here is to scroll from block 1 to 5, and then when the 5th block is visible, switch to 1 again. The switch will not be noticeable because 1 and 5 blocks are exactly the same.

That’s it, run the app and you will see infinite animation.

 

3. Create InfiniteScroller component

Let’s move everything into a separate view called InfiniteScroller that can be reused.


struct InfiniteScroller<Content: View>: View {
    var contentWidth: CGFloat
    var content: (() -> Content)
    
    @State
    var xOffset: CGFloat = 0

    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 0) {
                    content()
                    content()
                }
                .offset(x: xOffset, y: 0)
        }
        .disabled(true)
        .onAppear {
            withAnimation(.linear(duration: 5).repeatForever(autoreverses: false)) {
                xOffset = -contentWidth
            }
        }
    }
}

And here’s its usage example.


struct ColorAnimationView: View {
        
    var body: some View {
        GeometryReader { geometry in
            let size = geometry.size.width / 4
            
            InfiniteScroller(contentWidth: size * 4) {
                HStack(spacing: 0) {
                    ColorView(size: size, color: Color.green)
                    ColorView(size: size, color: Color.white)
                    ColorView(size: size, color: Color.pink)
                    ColorView(size: size, color: Color.cyan)
                }
            }
        }
    }
}

Well, that’s pretty easy, right? We just need to wrap the views inside InfiniteScroller and we are done!

Conclusion

Well, that’s it for today, hope you learned something!

As you might have observed, creating animations with SwiftUI is very easy. Today, we have just explored the tip of the iceberg. There are so many creative animations you can implement with SwiftUI. I have previously explored more animations in 2 part series, feel free to check them out if you want to learn more.

Keep animating!!


jimmy image
Jimmy Sanghani
Jimmy Sanghani is a tech nomad and cofounder at Canopas helping businesses use new age leverage - Code and Media - to grow their revenue exponentially. With over a decade of experience in both web and mobile app development, he has helped 100+ clients transform their visions into impactful digital solutions. With his team, he's helping clients navigate the digital landscape and achieve their objectives, one successful project at a time.


jimmy image
Jimmy Sanghani
Jimmy Sanghani is a tech nomad and cofounder at Canopas helping businesses use new age leverage - Code and Media - to grow their revenue exponentially. With over a decade of experience in both web and mobile app development, he has helped 100+ clients transform their visions into impactful digital solutions. With his team, he's helping clients navigate the digital landscape and achieve their objectives, one successful project at a time.

Whether you need...

  • *
    High-performing mobile apps
  • *
    Bulletproof cloud solutions
  • *
    Custom solutions for your business.
Bring us your toughest challenge and we'll show you the path to a sleek solution.
Talk To Our Experts
footer
Subscribe Here!
Follow us on
2024 Canopas Software LLP. All rights reserved.