Home 5 Underrated SwiftUI Modifiers
Post
Cancel

5 Underrated SwiftUI Modifiers

SwiftUI is a powerful declarative framework for building user interfaces in Swift. For iOS developers, it’s essentially the best thing since sliced bread. One of the neat little things that allows us to declaratively specify how we want our views to behave and look are modifiers. SwiftUI has an extensive collection of modifiers, While there are many well-known ones, there are also some underrated modifiers that can enhance your app’s functionality and appearance. Here are five underrated modifiers in SwiftUI:

Refreshable

The refreshable modifier allows you to add pull-to-refresh functionality to a SwiftUI view. By attaching this modifier to a List or a ScrollView, you can enable users to refresh the content by pulling down on the view. This modifier is handy for displaying dynamic data that needs to be updated periodically. It’s SwiftUI’s equivalent of collectionView.refreshControl = UIRefreshControl. SwiftUI will automatically hide and show a loading spinner as our refresh action is being performed, and will even ensure that no duplicate refresh actions are being performed at the same time. Really cool!

As an added bonus — given that Swift supports first class functions — we can even pass our view model’s reload method directly to the refreshable modifier, which gives us a slightly more compact implementation:

1
2
3
4
5
6
7
8
9
10
11
12
List {
    // List items here
}
.refreshable {
    // Code to refresh data
}

ScrollView {
    Text("Pull to refresh")
}
.refreshable(action: viewModel.reload)

Redacted

The redacted modifier is a powerful and often overlooked modifier that allows you to partially or fully redact the content of a view. It is particularly useful when handling sensitive or private information. By applying the .redacted modifier, you can hide or obfuscate specific parts of your view’s content.

The redacted modifier can be applied to any view, and it supports two modes: .redacted(reason:) and .unredacted.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
struct RedactedViewExample: View {
    @State private var isRedacted = false
    
    var body: some View {
        VStack(spacing: 20) {
            Image("stubImage1")
                .resizable()
                .frame(width: 100, height: 100)
                .clipShape(Circle())
                .redacted(reason: isRedacted ? .placeholder : .init())

            Text("John Doe")
                .font(.title)
                .redacted(reason: isRedacted ? .placeholder : .init())

            Button(action: {
                // Action when the button is tapped
            }) {
                Text("Bank Info")
                    .bold()
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
            .redacted(reason: isRedacted ? .placeholder : .init())

            Button(action: {
                isRedacted.toggle()
            }) {
                Text(isRedacted ? "Show Profile" : "Hide Profile")
            }
        }
        .padding()
    }
}

Transition

The transition modifier enables you to apply custom animations when a view appears or disappears. You can use this modifier to create smooth transitions between different states of your app’s UI. There are various built-in transition animations available, or you can even define your own custom transitions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
struct ContentView: View {
    @State private var showFirstImage = true
    
    var body: some View {
        VStack {
            if showFirstImage {
                Image("firstImage")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(width: 50, width: 50)
                    .transition(.push(from: .leading)) // Transition modifier for the first image
            } else {
                Image("secondImage")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(width: 50, width: 50)
                    .transition(.push(from: .trailing)) // Transition modifier for the second image
            }
            
            Button("Switch Images") {
                withAnimation {
                    showFirstImage.toggle()
                }
            }
        }
    }
}

AnyLayout

The AnyLayout modifier allows you to create flexible layouts by combining multiple views into a single layout. With this modifier, you can dynamically switch between different layouts based on certain conditions or user interactions. It provides more control over the arrangement and composition of your views.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
struct ContentView: View {
    @State private var useVStack = false

    var body: some View {
        let dynamicLayout = useVStack ? AnyLayout(VStackLayout()) : AnyLayout(HStackLayout())
        
        dynamicLayout {
            profileImages
        }
        .onTapGesture {
            withAnimation(.easeInOut(duration: 1)) {
                useVStack.toggle()
            }
        }

    }

    var profileImages: some View {
        Group {
            Image("image1")
                .resizable()
                .scaledToFill()
                .frame(width: 55, height: 55)
                .clipShape(Circle())
            
            Image("image2")
                .resizable()
                .scaledToFill()
                .frame(width: 55, height: 55)
                .clipShape(Circle())
        }
    }
}

When you change useVStack state you will get a nice transition animation of stacks.

Content Transition

The content transition allows us to animate the content of a view. This can be really neat for things like font change animation for example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct ContentView: View {
    @State private var showBoldness = false
    
    var body: some View {
        Text("AWESOME DAY!")
            .font(.largeTitle)
            .fontWeight(showBoldness ? .black : .thin)
            .foregroundColor(showBoldness ? .yellow : .blue)
            .contentTransition(.interpolate)
            .onTapGesture {
                withAnimation(.easeInOut(duration: 1)) {
                    showBoldness.toggle()
                }
            }
        
    }
}

Bye

As you can see SwiftUI offers a range of underrated modifiers that can greatly enhance your app’s UI. With these modifiers we can achieve flexible layouts, animated content changes, and privacy-friendly displays. These modifiers unlock new possibilities and empower us to create exceptional user experiences with SwiftUI’s declarative approach.

This post is licensed under CC BY 4.0 by the author.