• SwiftUI 3D Scroll Effect
  • Jean-marc Boullianne
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: chaingangway
  • Proofread by: LSvih

3D Scroll effect with SwiftUI

Let’s preview the 3D Scroll that we’re going to do today. After this tutorial, you can add this 3D effect to any custom SwiftUI view in your App. Let’s start this tutorial.

An introduction to

First, create a new SwiftUI view. To illustrate, in this new view I will show a list of rectangles with various colors and name the new view ColorList.

import SwiftUI

struct ColorList: View {
    var body: some View {
        Text("Hello, World!")}}struct ColorList_Previews: PreviewProvider {
    static var previews: some View {
        ColorList()}}Copy the code

Color data

In the structure of the view, add a variable to record the color.

var colors: [Color]
Copy the code

Implement this list

Inside the body variable, remove the placeholder Text. Add an HStack to the ScrollView nesting as follows:

var body: some View {
    ScrollView(.horizontal, showsIndicators: false) {
        HStack(alignment: .center, spacing: 50) {}}}Copy the code

Show the rectangular

We use ForEach inside the HStack to create rectangles of different colors based on the data in colors. In addition, I modified the rectangular frame to look more like a traditional UI layout.

var body: some View {
    ScrollView(.horizontal, showsIndicators: false) {
        HStack(alignment: .center, spacing: 20) {
            ForEach(colors, id: \.self) { color in
                Rectangle()
                    .foregroundColor(color)
                    .frame(width: 200, height: 300, alignment: .center)
            }
        }
    }
}
Copy the code

Pass in the Preview structure the following color parameters:

struct ColorList_Previews: PreviewProvider {
    static var previews: some View {
        ColorList(colors: [.blue, .green, .orange, .red, .gray, .pink, .yellow])
    }
}
Copy the code

You can see what it looks like below:

Add 3D effect

First, you nest the Rectangle in the GeometryReader. This way, as Rectangle moves across the screen, we get a reference to its Frame.

var body: some View {
    ScrollView(.horizontal, showsIndicators: false) {
        HStack(alignment: .center, spacing: 230) {
            ForEach(colors, id: \.self) { color in
                GeometryReader { geometry in
                    Rectangle()
                        .foregroundColor(color)
                        .frame(width: 200, height: 300, alignment: .center)
                }
            }
        }
    }
}
Copy the code

Based on the usage requirements of the GeometryReader, we need to modify the spacing property of the HStack defined above.

Add the following line to Rectangle.

.rotation3DEffect(Angle(degrees: (Double(geometry.frame(in: .global).minX) - 210) / -20), axis: (x: 0, y: 1.0, z: 0))
Copy the code

The Angle parameter of this method changes as Rectangle moves across the screen. Focus on the.frame(in:) function, which gives you the Rectangle’s CGRect minX variable to calculate angles.

The axis argument is a tuple type that defines which axes should change when using the Angle argument you pass in. In this case, the Y-axis.

Documentation for the rotation3DEffect() method can be found here on the Apple website.

Next, run the case. You can see the rectangles rotate as they move across the screen.

I also changed the cornerRadius property of the rectangle and added a drop shadow effect to make it more beautiful.

The final result

struct ColorList: View {
    
    var colors:[Color]
    
    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(alignment: .center, spacing: 230) {
                ForEach(colors, id: \.self) { color in
                    GeometryReader { geometry in
                        Rectangle()
                            .foregroundColor(color)
                            .frame(width: 200, height: 300, alignment: .center)
                            .cornerRadius(16)
                            .shadow(color: Color.black.opacity(0.2), radius: 20, x: 0, y: 0)
                            .rotation3DEffect(Angle(degrees: (Double(geometry.frame(in: .global).minX) - 210) / -20), axis: (x: 0, y: 1.0, z: 0))
                    }
                }
            }.padding(.horizontal, 210)}}}Copy the code

The end of the

If you enjoyed this article, you can subscribe to our website using this link. If you are not reading this article at TrailingClosure.com, you may want to visit this site in the future.

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.