SwiftUI Smart ViewModifiers

How to use View Modifiers in Swift UI and how to improve usage.

Emin DENİZ
Orion Innovation techClub

--

SwiftUI logo

SwiftUI has been in our lives for more than 4 years and has many excellent features to design modern applications. In this article, I will explain View Modifiers to you.

For the purpose of this article, I will give the most simplistic UI design. It can be not a beautiful UI, but it will explain the modifiers.

Designing Custom Text Elements in SwiftUI

Let’s assume that we want to design an application with texts with 4 different styles. Which are;

  • Title of the application
  • Section title
  • Section content
  • Reference section

If I want to design such UI I only need to use VStack, Spacers, and Text views. Let’s see how can I design each text one by one.

Title of the app

The title of the app is easy to customize. I just need to add font and foreground color

Text("Here is my app")
.font(.title.weight(.bold))
.foregroundColor()

That is pretty straightforward. But for the next text views, it is a bit more complicated.

Section Title

I need to have a foreground style, frame, background, cornerRadius, and font properties to design the section title.

Text("What is Lorem Ipsum?")
.padding()
.foregroundStyle(.white)
.frame(width: UIScreen.main.bounds.width - 10, height: 50, alignment: .leading)
.background(.cyan)
.cornerRadius(40)
.font(.title)

Ok, I have added more properties but the task is done now.

Section Content

I need to have the same properties with different values for the section content.

Text(“Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.”)    .padding()
.foregroundStyle(.white)
.frame(width: UIScreen.main.bounds.width — 20, height: 200, alignment: .center)
.background(.indigo)
.cornerRadius(20)
.font(.body)

Reference Section

For this section, I need to have padding, frame, background and font properties.

Text(“Reference: https://www.lipsum.com")
.padding()
.frame(width: UIScreen.main.bounds.width, alignment: .center)
.background(.orange)
.font(.footnote.weight(.bold))

So we see how can we design each piece. Let’s see the combined form of these pieces to create our complete UI.

Sweet! We completed our design just like that. 🎉

But we can do it better!

As you can see we use similar properties too much. Can we implement this design without repeated codes?

We are using some elements multiple times (Section title and section content). If we want to reuse an element multiple times we should have the same styling to have a good UI. In this approach, we are trying to have the same styling with sing same properties again and again. This can lead to two problems;

  • First, it is possible to add a property to the first view and forget to add it to the second view.
  • Second, if we want to update the appearance of an element we need to update multiple lines of code.

At last, we are using some custom designs a lot in the view. Like;

.frame(width: UIScreen.main.bounds.width — 20, height: 200, alignment: .center)

I don’t know your feelings about seeing this code block in ContentView, but for me, this can be abstracted.

Let’s see how can we achieve those items.

View Modifiers in SwiftUI

SwiftUI has a protocol called ViewModifier that allows developers to customize views easily. We can create and update fixed styles easily with ViewModifiers. Let’s see how we can achieve this.

First, create a file called TextViewModifiers and add a struct called AppTitleTextModifiers. Then implement ViewModifier protocol in AppTitleTextModifiers. After that, you will see an error in Xcode.

When you implement ViewModifier protocol you must conform body function in that struct. Let’s add it.

Title of the app with ViewModifier

struct AppTitleTextModifiers : ViewModifier {
func body(content: Content) -> some View {
content
.font(.title.weight(.bold))
.foregroundColor(.red)
}
}

So we created our first view modifier, let’s see how we can use it.

Text("Here is my app")
.modifier(AppTitleTextModifiers())

That is it!

Section title with ViewModifier

For the section title, we have much more properties to add.

struct SectionTitleTextModifiers : ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.foregroundStyle(.white)
.frame(width: UIScreen.main.bounds.width - 10, height: 50, alignment: .leading)
.background(.cyan)
.cornerRadius(40)
.font(.title)
}
}

Event with more properties usage is the same.

Text("What is Lorem Ipsum?")
.modifier(SectionTitleTextModifiers())

After adding all view modifiers here is the complete view of our Text Modifiers file.

And here is the updated ContentView file with modifiers.

We easily customize our UI with the same styling. 🥳

Pushing It Further

So far we achieve to design the same UI with the view modifiers much more clearly. Is it possible to harvest the power of the view modifiers more? Yes, it is.

It is not always a good approach but in some cases, we might need to customize styling as well. Let’s say we want to add sub-section content to our app.

Sub-section content has 3 differences from section content. It has a yellow background, the text is right aligned and the text color is black. We can create SubSectionContentTextModifiers for this style and use them in our application. But some UI elements are not frequently used in applications like this one. For these kinds of UI elements, I prefer to have flexible view modifiers. Let’s see how we can do that.

Update the SectionContentTextModifiers to have init function.

struct SectionContentTextModifiers : ViewModifier {var alignment: Alignment
var backgroundColor:Color
var foregroundColor:Color

init( alignment: Alignment = .center,
backgroundColor:Color = .indigo,
foregroundColor:Color = .white) {
self.alignment = alignment
self.backgroundColor = backgroundColor
self.foregroundColor = foregroundColor
}

func body(content: Content) -> some View {

content
.padding()
.foregroundStyle(foregroundColor)
.frame(width: UIScreen.main.bounds.width — 20, height: 200, alignment: alignment)
.background(backgroundColor)
.cornerRadius(20)
}
}

The trick is here to use default variables on init. When you use default variables you don’t have to set alignment, backgroundColor and foregroundColor. Now we can use SectionContentTextModifiers for the sub-section like this;

Text(“Sub section content“)
.modifier(SectionContentTextModifiers(alignment: .trailing,
backgroundColor: .yellow,
foregroundColor: .black))

So here is the final form of our TextViewModifiers and ContentView file.

The final form of TextViewModifiers
The final form of ContentView

Conclusion

ViewModifiers in SwiftUI is an excellent tool to create custom elements in your application. Using that you can create specific styles for your brand and easily reuse it. If you ever need to update all of your styles in the application, all you need to update your view modifiers.

I hope you enjoy reading it.

--

--