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.