New in SwiftUI 3: Material in SwiftUI 3


Material is another great feature that was introduced at WWDC21 and with the release of SwiftUI 3.

UIVisualEffectView has been around in UIKit for so long that I even lost the track of time 🤓🤓

Material is a ShapeStyle and provides a background material which can be applied to create a blur effect. There are predefined types available and they are supported under dark and light mode. Let’s take a look at them.

We will start with a simple ZStack then will add linear gradient and VStack inside. VStack will contain text views.

struct MaterialExample: View {
    let colors: [Color] = [.blue, .purple, .pink, .red, .yellow, .orange, .brown]
    var body: some View {
        ZStack {
            LinearGradient(colors: colors, startPoint: .top, endPoint: .bottom)
            VStack(spacing: 50) {
                Text("Devtechie")
                Text("Devtechie")
                Text("Devtechie")
                Text("Devtechie")
                Text("Devtechie")
            }
            .font(.title2)
            .foregroundColor(.secondary)
        }.edgesIgnoringSafeArea(.all)
    }
}
Lets apply background material to text views. To give extra spacing around text, we will add padding as well

struct MaterialExample: View {
    let colors: [Color] = [.blue, .purple, .pink, .red, .yellow, .orange, .brown]
    var body: some View {
        ZStack {
            LinearGradient(colors: colors, startPoint: .top, endPoint: .bottom)
            VStack(spacing: 50) {
                Text("Devtechie")
                    .padding()
                    .background(Material.ultraThinMaterial)
                
                Text("Devtechie")
                    .padding()
                    .background(Material.thinMaterial)
                
                Text("Devtechie")
                    .padding()
                    .background(Material.regularMaterial)
                
                Text("Devtechie")
                    .padding()
                    .background(Material.thickMaterial)
                
                Text("Devtechie")
                    .padding()
                    .background(Material.ultraThickMaterial)
                
                Text("Devtechie")
                    .padding()
                    .background(Material.bar)
                
            }
            .font(.title2)
            .foregroundColor(.secondary)
        }.edgesIgnoringSafeArea(.all)
    }
}
Notice the difference between different material types. Let’s try this out in dark mode as well.

While applying material on the view, we can add Shape as well to the view:

.background(Material.thickMaterial, in: RoundedRectangle(cornerRadius: 10.0))
Complete code with shape change:

struct MaterialExample: View {
    let colors: [Color] = [.blue, .purple, .pink, .red, .yellow, .orange, .brown]
    var body: some View {
        ZStack {
            LinearGradient(colors: colors, startPoint: .top, endPoint: .bottom)
            VStack(spacing: 50) {
                Text("Devtechie")
                    .padding()
                    .background(Material.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 10.0))
                
                Text("Devtechie")
                    .padding()
                    .background(Material.thinMaterial, in: RoundedRectangle(cornerRadius: 10.0))
                
                Text("Devtechie")
                    .padding()
                    .background(Material.regularMaterial, in: RoundedRectangle(cornerRadius: 10.0))
                
                Text("Devtechie")
                    .padding()
                    .background(Material.thickMaterial, in: RoundedRectangle(cornerRadius: 10.0))
                
                Text("Devtechie")
                    .padding()
                    .background(Material.ultraThickMaterial, in: RoundedRectangle(cornerRadius: 10.0))
                
                Text("Devtechie")
                    .padding()
                    .background(Material.bar, in: RoundedRectangle(cornerRadius: 10.0))
                
            }
            .font(.title2)
            .foregroundColor(.secondary)
        }.edgesIgnoringSafeArea(.all)
    }
}
We are repeating a lot of code so lets refactor this to move material application out into a function.

struct MaterialExample: View {
    let colors: [Color] = [.blue, .purple, .pink, .red, .yellow, .orange, .brown]
    var body: some View {
        ZStack {
            LinearGradient(colors: colors, startPoint: .top, endPoint: .bottom)
            VStack(spacing: 50) {
                viewWithMaterial(text: "DevTechie", subtext: "ultraThinMaterial", material: .ultraThinMaterial)
                
                viewWithMaterial(text: "DevTechie", subtext: "thinMaterial", material: .thinMaterial)
                
                viewWithMaterial(text: "DevTechie", subtext: "regularMaterial", material: .regularMaterial)
                
                viewWithMaterial(text: "DevTechie", subtext: "thickMaterial", material: .thickMaterial)
                
                viewWithMaterial(text: "DevTechie", subtext: "ultraThickMaterial", material: .ultraThickMaterial)
                
                viewWithMaterial(text: "DevTechie", subtext: "bar", material: .bar)
            }
            .foregroundColor(.secondary)
        }.edgesIgnoringSafeArea(.all)
    }
    
    private func viewWithMaterial(text: String, subtext: String, material: Material) -> some View {
        VStack {
            Text(text)
                .font(.title2)
            Text(subtext)
                .font(.subheadline)
        }
        .padding()
        .frame(maxWidth: .infinity)
        .background(material)
    }
}
Here is how our view looks now:



With that, we have reached the end of this article. Thank you once again for reading, if you liked it, don’t forget to subscribe our newsletter.