Reader small image

You're reading from  SwiftUI Essentials – iOS 14 Edition

Product typeBook
Published inMay 2021
Reading LevelBeginner
PublisherPackt
ISBN-139781801813228
Edition1st Edition
Languages
Tools
Right arrow
Author (1)
Neil Smyth
Neil Smyth
author image
Neil Smyth

Neil Smyth has over 25 years of experience in the IT industry, including roles in software development and enterprise-level UNIX and Linux system administration. In addition to a bachelor’s degree in information technology, he also holds A+, Security+, Network+, Project+, and Microsoft Certified Professional certifications and is a CIW Database Design Specialist. Neil is the co-founder and CEO of Payload Media, Inc. (a technical content publishing company), and the author of the Essentials range of programming and system administration books.
Read more about Neil Smyth

Right arrow

20. Creating Custom Views with SwiftUI

A key step in learning to develop apps using SwiftUI is learning how to declare user interface layouts both by making use of the built-in SwiftUI views as well as building your own custom views. This chapter will introduce the basic concepts of SwiftUI views and outline the syntax used to declare user interface layouts and modify view appearance and behavior.

20.1 SwiftUI Views

User interface layouts are composed in SwiftUI by using, creating and combining views. An important first step is to understand what is meant by the term “view”. Views in SwiftUI are declared as structures that conform to the View protocol. In order to conform with the View protocol, a structure is required to contain a body property and it is within this body property that the view is declared.

SwiftUI includes a wide range of built-in views that can be used when constructing a user interface including text label, button, text field, menu, toggle and layout manager views. Each of these is a self-contained instance that complies with the View protocol. When building an app with SwiftUI you will use these views to create custom views of your own which, when combined, constitute the appearance and behavior of your user interface.

These custom views will range from subviews that encapsulate a reusable subset of view components (perhaps a secure text...

20.2 Creating a Basic View

In Xcode, custom views are contained within SwiftUI View files. When a new SwiftUI project is created, Xcode will create a single SwiftUI View file containing a single custom view consisting of a single Text view component. Additional view files can be added to the project by selecting the File -> New -> File… menu option and choosing the SwiftUI View file entry from the template screen.

The default SwiftUI View file is named ContentView.swift and reads as follows:

import SwiftUI

 

struct ContentView: View {

    var body: some View {

        Text("Hello, world!")

            .padding()

    }

}

 

struct ContentView_Previews: PreviewProvider {

    static var previews: some View {

        ContentView...

20.3 Adding Additional Views

Additional views can be added to a parent view by placing them in the body. The body property, however, is configured to return a single view. Adding an additional view, as is the case in the following example, will cause Xcode to create a second preview containing just the “Goodbye, world!” text view:

struct ContentView: View {

    var body: some View {

        Text("Hello, world!")

            .padding()

        Text("Goodbye, world!")

    }

}

To correctly add additional views, those views must be placed in a container view such as a stack or form. The above example could, therefore, be modified to place the two Text views in a vertical stack (VStack) view which, as the name suggests, positions views vertically within...

20.4 Working with Subviews

Apple recommends that views be kept as small and lightweight as possible. This promotes the creation of reusable components, makes view declarations easier to maintain and results in more efficient layout rendering.

If you find that a custom view declaration has become large and complex, identify areas of the view that can be extracted into a subview. As a very simplistic example, the HStack view in the above example could be extracted as a subview named “MyHStackView” as follows:

struct ContentView: View {

    var body: some View {

        VStack {

            VStack {

                Text("Text 1")

                Text("Text 2"...

20.5 Views as Properties

In addition to creating subviews, views may also be assigned to properties as a way to organize complex view hierarchies. Consider the following example view declaration:

struct ContentView: View {

    

    var body: some View {

        

        VStack {

            Text("Main Title")

                .font(.largeTitle)

            HStack {

                Text("Car Image")

                Image(systemName: "car.fill")

 ...

20.6 Modifying Views

It is unlikely that any of the views provided with SwiftUI will appear and behave exactly as required without some form of customization. These changes are made by applying modifiers to the views.

All SwiftUI views have sets of modifiers which can be applied to make appearance and behavior changes. These modifiers take the form of methods that are called on the instance of the view and essentially wrap the original view inside another view which applies the necessary changes. This means that modifiers can be chained together to apply multiple modifications to the same view. The following, for example, changes the font and foreground color of a Text view:

Text("Text 1")

    .font(.headline)

    .foregroundColor(.red)

Similarly, the following example uses modifiers to configure an Image view to be resizable with the aspect ratio set to fit proportionally within the available space:

Image(systemName...

20.7 Working with Text Styles

In the above example the font used to display text on a view was declared using a built-in text style (in this case the large title style).

iOS provides a way for the user to select a preferred text size which applications are expected to adopt when displaying text. The current text size can be configured on a device via the Settings -> Display & Brightness -> Text Size screen which provides a slider to adjust the font size as shown below:

Figure 20-2

If a font has been declared on a view using a text style, the text size will dynamically adapt to the user’s preferred font size. Almost without exception, the built-in iOS apps adopt the preferred size setting selected by the user when displaying text and Apple recommends that third-party apps also conform to the user’s chosen text size. The following text style options are currently available:

Large Title

Title, Title2, Title 3

Headline...

20.8 Modifier Ordering

When chaining modifiers, it is important to be aware that the order in which they are applied can be significant. Both border and padding modifiers have been applied to the following Text view.

Text("Sample Text")

    .border(Color.black)

    .padding()

The border modifier draws a black border around the view and the padding modifier adds space around the view. When the above view is rendered it will appear as shown in Figure 20-4:

Figure 20-4

Given that padding has been applied to the text, it might be reasonable to expect there to be a gap between the text and the border. In fact, the border was only applied to the original Text view. Padding was then applied to the modified view returned by the border modifier. The padding is still applied to the view, but outside of the border. For the border to encompass the padding, the order of the modifiers needs to be changed so that the border...

20.9 Custom Modifiers

SwiftUI also allows you to create your own custom modifiers. This can be particularly useful if you have a standard set of modifiers that are frequently applied to views. Suppose that the following modifiers are a common requirement within your view declarations:

Text("Text 1")

    .font(.largeTitle)

    .background(Color.white)

    .border(Color.gray, width: 0.2)

    .shadow(color: Color.black, radius: 5, x: 0, y: 5)

Instead of applying these four modifiers each time text with this appearance is required, a better solution is to group them into a custom modifier and then reference that modifier each time the modification is needed. Custom modifiers are declared as structs that conform to the ViewModifier protocol and, in this instance, might be implemented as follows:

struct StandardTitle: ViewModifier {

   func body(content: Content...

20.10 Basic Event Handling

Although SwiftUI is described as being data driven, it is still necessary to handle the events that are generated when a user interacts with the views in the user interface. Some views, such as the Button view, are provided solely for the purpose of soliciting user interaction. In fact, the Button view can be used to turn a variety of different views into a “clickable” button. A Button view needs to be declared with the action method to be called when a click is detected together with the view to act as the button content. It is possible, for example, to designate an entire stack of views as a single button. In most cases, however, a Text view will typically be used as the Button content. In the following implementation, a Button view is used to wrap a Text view which, when clicked, will call a method named buttonPressed():

struct ContentView: View {

    var body: some View {

      ...

20.11 Building Custom Container Views

As outlined earlier in this chapter, subviews provide a useful way to divide a view declaration into small, lightweight and reusable blocks. One limitation of subviews, however, is that the content of the container view is static. In other words, it is not possible to dynamically specify the views that are to be included at the point that a subview is included in a layout. The only children included in the subview are those that are specified in the original declaration.

Consider the following subview which consists of three TextViews contained within a VStack and modified with custom spacing and font settings.

struct MyVStack: View {

    var body: some View {

        VStack(spacing: 10) {

            Text("Text Item 1")

            Text("...

20.12 Working with the Label View

The Label view is different from most other SwiftUI views in that it comprises two elements in the form of an icon and text positioned side-by-side. The image can take the form of any image asset, a SwiftUI Shape rendering or an SF Symbol.

SF Symbols is a collection of over 1500 scalable vector drawings available for use when developing apps for Apple platforms and designed to complement Apple’s San Francisco system font.

The full set of symbols can be searched and browsed by installing the SF Symbols macOS app available from the following URL:

https://developer.apple.com/design/downloads/SF-Symbols.dmg

The following is an example of the Label view using an SF Symbol together with a font() modifier to increase the size of the icon and text:

Label("Welcome to SwiftUI", systemImage: "person.circle.fill")

    .font(.largeTitle)

The above view will be rendered as shown in Figure 20-6 below...

20.13 Summary

SwiftUI user interfaces are declared in SwiftUI View files and are composed of components that conform to the View protocol. To conform with the View protocol a structure must contain a property named body which is itself a View.

SwiftUI provides a library of built-in components for use when designing user interface layouts. The appearance and behavior of a view can be configured by applying modifiers, and views can be modified and grouped together to create custom views and subviews. Similarly, custom container views can be created using the ViewBuilder closure property.

When a modifier is applied to a view, a new modified view is returned and subsequent modifiers are then applied to this modified view. This can have significant implications for the order in which modifiers are applied to a view.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
SwiftUI Essentials – iOS 14 Edition
Published in: May 2021Publisher: PacktISBN-13: 9781801813228
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at £13.99/month. Cancel anytime

Author (1)

author image
Neil Smyth

Neil Smyth has over 25 years of experience in the IT industry, including roles in software development and enterprise-level UNIX and Linux system administration. In addition to a bachelor’s degree in information technology, he also holds A+, Security+, Network+, Project+, and Microsoft Certified Professional certifications and is a CIW Database Design Specialist. Neil is the co-founder and CEO of Payload Media, Inc. (a technical content publishing company), and the author of the Essentials range of programming and system administration books.
Read more about Neil Smyth