Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
SwiftUI Cookbook
SwiftUI Cookbook

SwiftUI Cookbook: Discover solutions and best practices to tackle the most common problems while building SwiftUI apps

Arrow left icon
Profile Icon Giordano Scalzo Profile Icon Nzokwe
Arrow right icon
Free Trial
Full star icon Full star icon Full star icon Full star icon Half star icon 4.8 (10 Ratings)
Paperback Oct 2020 614 pages 1st Edition
eBook
Can$38.99 Can$55.99
Paperback
Can$69.99
Subscription
Free Trial
Arrow left icon
Profile Icon Giordano Scalzo Profile Icon Nzokwe
Arrow right icon
Free Trial
Full star icon Full star icon Full star icon Full star icon Half star icon 4.8 (10 Ratings)
Paperback Oct 2020 614 pages 1st Edition
eBook
Can$38.99 Can$55.99
Paperback
Can$69.99
Subscription
Free Trial
eBook
Can$38.99 Can$55.99
Paperback
Can$69.99
Subscription
Free Trial

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing
Table of content icon View table of contents Preview book icon Preview Book

SwiftUI Cookbook

Chapter 2: Going Beyond the Single Component with Lists and Scroll Views

In this chapter, we'll learn how to display lists in SwiftUI. List views are similar to UITableViews in UIKit but are significantly simpler to use. No storyboards or prototype cells are required, and we do not need to know how many rows there are. SwiftUI's lists are designed to be modular so that you can build bigger things from smaller components.

We'll also look at lazy stacks and lazy grids, which are used to optimize the display of large amounts of data by loading only the subset of the content that is currently being displayed or is about to be displayed. Lastly, we'll take a look at how to present hierarchical data in an expanding list with sections that can be expanded or collapsed.

By the end of this chapter, you will understand how to display lists of static or dynamic items, add or remove rows from lists, edit lists, add sections to list views, and much more.

In this chapter, we will cover the following recipes:

  • Using scroll views
  • Creating a list of static items
  • Using custom rows in a list
  • Adding rows to a list
  • Deleting rows from a list
  • Editing a list
  • Moving rows in a list
  • Adding sections to a list
  • Using LazyHStack and LazyVStack (iOS 14+)
  • Using LazyHGrid and LazyVGrid (iOS 14+)
  • Using ScrollViewReader (iOS 14+)
  • Using expanding lists (iOS 14+)
  • Using DisclosureGroup to hide and show content (iOS 14+)

Technical requirements

The code in this chapter is based on Xcode 12 and iOS 13. However, some recipes are only compatible with iOS 14 and higher.

You can find the code in the book's GitHub repository at https://github.com/PacktPublishing/SwiftUI-Cookbook/tree/master/Chapter02%20-%20Lists%20and%20ScrollViews.

Using scroll views

SwiftUI scroll views are used to easily create scrolling containers. They automatically size themselves to the area where they are placed. Scroll views are vertical by default and can be made to scroll horizontally or vertically by passing in the .horizontal() or .vertical() modifiers as the first parameter to the scroll view.

Getting ready

Let's start by creating a SwiftUI project called ScrollViewApp.

Optional: Download the San Francisco (SF) Symbols app here: https://developer.apple.com/sf-symbols/.

SF Symbols is a set of over 2,400 symbols provided by Apple. They follow Apple's San Francisco system font and automatically ensure optical vertical alignment for different sizes and weights.

How to do it…

We will add two scroll views to a VStack component: one horizontal and one vertical. Each scroll view will contain SF symbols for the letters A–L:

  1. Between the ContentView struct declaration and its body, create an array of SF symbol names called imageNames. Add the strings for SF symbols A–L:
    let imageNames = [
            "a.circle.fill",
            "b.circle.fill",
            "c.circle.fill",
            "d.circle.fill",
            "e.circle.fill",
            "f.circle.fill",
            "g.circle.fill",
            "h.circle.fill",
            "i.circle.fill",
            "j.circle.fill",
            "k.circle.fill",
            "l.circle.fill",
        ]
  2. Add a VStack component and scroll views to the app:
        var body: some View {
            VStack{
                ScrollView {
                        ForEach(self.imageNames, id: \.self)                    { name in
                            Image(systemName: name)
                                .font(.largeTitle)
                                .foregroundColor(Color.                                yellow)
                                .frame(width: 50, height: 50)
                                .background(Color.blue)
                        }
                }
                .frame(width:50, height:200)
                
                ScrollView(.horizontal, showsIndicators:               false) {
                    HStack{
                        ForEach(self.imageNames, id: \.self)                    { name in
                            Image(systemName: name)
                                .font(.largeTitle)
                                .foregroundColor(Color.                               yellow)
                                .frame(width: 50, height: 50)
                                .background(Color.blue)
                        }
                    }
                }
            }
        }

    The result is a view with a vertical and horizontal scroll view:

Figure 2.1 – App with horizontal and vertical scroll views

Figure 2.1 – App with horizontal and vertical scroll views

How it works…

VStack allows us to display multiple scroll views within the ContentView struct's body.

By default, scroll views display items vertically. The first ScrollView component in VStack displays items in a vertical way, even though no axis was specified.

Within the first ScrollView component, a ForEach loop is used to iterate over a static array and display the contents. In this case, the ForEach loop takes two parameters: the array we are iterating over and an identifier, id: \.self, used to distinguish between the items being displayed. The id parameter would not be required if the collection used conformed to the Identifiable protocol.

Two parameters are passed to the second ScrollView component: the axis and showIndicators (ScrollView(.horizontal, showsIndicators: false). The .horizontal axis parameter causes content to be horizontal, and showIndictors:false prevents the scrollbar indicator from appearing in the view.

See also

Refer to the Apple ScrollView documentation at https://developer.apple.com/documentation/swiftui/scrollview.

Creating a list of static items

Lists are similar to scroll views in that they are used to view a collection of items. Lists are used for larger datasets, whereas scroll views are used for smaller datasets; the reason being that list views do not load the whole dataset in memory at once and thus are more efficient at handling large data.

Getting ready

Let's start by creating a new SwiftUI app called StaticList.

How to do it…

We'll create a struct to hold weather information and an array of weather data. The data will then be used to create a view that provides weather information from several cities. Proceed as follows:

  1. Before the ContentView struct, create a struct called WeatherInfo with four properties: id, image, temp, and city:
    	struct WeatherInfo: Identifiable {
                var id = UUID()
                var image: String
                var temp: Int
                var city: String
    }
  2. Within the ContentView struct, create a weatherData property as an array of WeatherInfo:
        let weatherData: [WeatherInfo] = [
        WeatherInfo(image: "snow", temp: 5, city:"New York"),
        WeatherInfo(image: "cloud", temp:5, city:"Kansas       City"),
        WeatherInfo(image: "sun.max", temp: 80, city:"San       Francisco"),
        WeatherInfo(image: "snow", temp: 5, city:"Chicago"),
        WeatherInfo(image: "cloud.rain", temp: 49,      city:"Washington DC"),
        WeatherInfo(image: "cloud.heavyrain", temp: 60,       city:"Seattle"),
        WeatherInfo(image: "sun.min", temp: 75,       city:"Baltimore"),
        WeatherInfo(image: "sun.dust", temp: 65,       city:"Austin"),
        WeatherInfo(image: "sunset", temp: 78,       city:"Houston"),
        WeatherInfo(image: "moon", temp: 80, city:"Boston"),
        WeatherInfo(image: "moon.circle", temp: 45,      city:"denver"),
        WeatherInfo(image: "cloud.snow", temp: 8,      city:"Philadelphia"),
        WeatherInfo(image: "cloud.hail", temp: 5,       city:"Memphis"),
        WeatherInfo(image: "cloud.sleet", temp:5,       city:"Nashville"),
        WeatherInfo(image: "sun.max", temp: 80,       city:"San Francisco"),
        WeatherInfo(image: "cloud.sun", temp: 5,       city:"Atlanta"),
        WeatherInfo(image: "wind", temp: 88,       city:"Las Vegas"),
        WeatherInfo(image: "cloud.rain", temp: 60,       city:"Phoenix"),
        ]
  3. Add the List view to the ContentView body. The list should display the information contained in our weatherData array. Also add the font(size: 25) and padding() modifiers:
    List {
                ForEach(self.weatherData){ weather in
                    HStack {
                        Image(systemName: weather.image)
                            .frame(width: 50, alignment:                                .leading)
                        Text("\(weather.temp)°F")
                            .frame(width: 80, alignment:                                .leading)
                        Text(weather.city)
                    }
                    .font(.system(size: 25))
                    .padding()
                }
            }

    The resulting preview should be as follows:

Figure 2.2 – List in the weather app

Figure 2.2 – List in the weather app

How it works…

We started the recipe by creating a WeatherInfo struct to hold and model our weather data. The id = UUID() property creates a unique identifier for each variable we create from the struct. Adding the id property to our struct allows us to later use it within a ForEach loop without providing id: .\self parameter as seen in the previous recipe.

The ForEach loop within the List view iterates through the items in our model data and copies one item at a time to the weather variable declared on the same line.

The ForEach loop contains HStack because we would like to display multiple items on the same line – in this case, all the information contained in the weather variable.

The font(.system(size: 25)) and padding() modifiers add some padding to the list rows to improve the design and readability of the information.

The images displayed are based on SF Symbols, explained in Chapter 1, Using the Basic SwiftUI Views and Controls.

Using custom rows in a list

The number of lines of code required to display items in a list view row could vary from one to several lines of code. A custom list row is used when working with several lines of code within a list view row. Implementing custom lists improves modularity and readability, and allows code reuse.

Getting ready

Let's start by creating a new SwiftUI app called CustomRows.

How to do it…

We will reuse part of the code in the static list and clean it up to make it more modular. We create a separate file to hold the WeatherInfo struct, a separate SwiftUI file for the custom WeatherRow, and finally, we implement the components in the ContentView.swift file. The steps are as follows:

  1. Create a new Swift file called WeatherInfo by selecting File | New | File | Swift File or by pressing the ⌘ + N keys.
  2. Define the WeatherInfo struct within the WeatherInfo.swift file:
    struct WeatherInfo: Identifiable {
        var id = UUID()
        var image: String
        var temp: Int
        var city: String
    }
  3. Create a weatherData variable that holds an array of WeatherInfo:
    let weatherData: [WeatherInfo] = [
         WeatherInfo(image: "snow", temp: 5,        city:"New York"),
         WeatherInfo(image: "cloud", temp:5,        city:"Kansas City"),
         WeatherInfo(image: "sun.max", temp: 80,        city:"San Francisco"),
         WeatherInfo(image: "snow", temp: 5, city:"Chicago"),
         WeatherInfo(image: "cloud.rain", temp: 49,        city:"Washington DC"),
         WeatherInfo(image: "cloud.heavyrain", temp: 60,        city:"Seattle"),
         WeatherInfo(image: "sun.min", temp: 75,       city:"Baltimore"),
         WeatherInfo(image: "sun.dust", temp: 65,       city:"Austin"),
         WeatherInfo(image: "sunset", temp: 78,       city:"Houston"),
         WeatherInfo(image: "moon", temp: 80, city:"Boston"),
         WeatherInfo(image: "moon.circle", temp: 45,         city:"denver"),
         WeatherInfo(image: "cloud.snow", temp: 8,        city:"Philadelphia"),
         WeatherInfo(image: "cloud.hail", temp: 5,       city:"Memphis"),
         WeatherInfo(image: "cloud.sleet", temp:5,       city:"Nashville"),
         WeatherInfo(image: "sun.max", temp: 80,        city:"San Francisco"),
         WeatherInfo(image: "cloud.sun", temp: 5,        city:"Atlanta"),
         WeatherInfo(image: "wind", temp: 88,        city:"Las Vegas"),
         WeatherInfo(image: "cloud.rain", temp: 60,        city:"Phoenix"),
         ]
  4. Create a new SwiftUI file by selecting File | New | File | SwiftUI View or by pressing the + N keys.
  5. Name the file WeatherRow.
  6. Add the following code to design the look and functionality of the weather row:
    struct WeatherRow: View {
        var weather: WeatherInfo
        var body: some View {
            HStack {
                Image(systemName: weather.image)
                    .frame(width: 50, alignment: .leading)
                Text("\(weather.temp)°F")
                    .frame(width: 80, alignment: .leading)
                Text(weather.city)
            }
            .font(.system(size: 25))
            .padding()
        }
    }
  7. Add the following code to the WeatherRow_Previews struct to display information from a sample WeatherInfo struct instance:
    static var previews: some View {
            WeatherRow(weather: WeatherInfo(image: "snow",           temp: 5, city:"New York"))
        }
  8. The resulting WeatherRow.swift canvas preview should look as follows:
    Figure 2.3 – WeatherRow preview

    Figure 2.3 – WeatherRow preview

  9. Open the ContentView.swift file and create a list to display data using the custom WeatherRow component:
    var body: some View {
                List {
                    ForEach(weatherData){ weather in
                        WeatherRow(weather: weather)
                    }
                }
            }

    The resulting canvas preview should look as follows:

Figure 2.4 – CustomRowApp preview

Figure 2.4 – CustomRowApp preview

Run the app live preview and admire the work of your own hands.

How it works…

The WeatherInfo Swift file contains the description of the WeatherInfo struct. Our dataset, an array of WeatherInfo variables, was also declared in the file to make it available to other sections of the project.

The WeatherRow SwiftUI file contains the design we will use for each weather row. The weather property within WeatherRow will hold the WeatherInfo arguments passed to the view. HStack in the body of WeatherRow is used to display data from weather variables since a SwiftUI view can only return one view at a time. When displaying multiple views – an image view and two text views, in this case – the views are all encased in an HStack component. The .frame(width: 50, alignment: .leading) modifier added to the image and first text view sets the width used by the element it modifies to 50 units and the alignment to the .leading parameter.

Finally, the .font(.system(size: 25)) and .padding() modifiers are added to HStack to increase the text and image font sizes and add padding to all sides of WeatherRow.

Adding rows to a list

Lists are usually used to add, edit, remove, or display content from an existing dataset. In this section, we will go over the process of adding items to an already existing list.

Getting ready

Let's start by creating a new SwiftUI app called AddRowsToList.

How to do it…

To implement the add functionality, we will enclose the List view in NavigationView, and add a button to navigationBarItems that triggers the add function we will create. The steps are as follows:

  1. Create a state variable in the ContentView struct that holds an array of integers:
    @State var numbers = [1,2,3,4]
  2. Add a NavigationView component containing a List view to the ContentView body:
    NavigationView{
                List{
                    ForEach(self.numbers, id:\.self){                  number in
                        Text("\(number)")
                    }
                }
    }
  3. Add a navigationBarItems modifier to the list closing brace that contains a button that triggers the addItemToRow() function:
    .navigationBarItems(trailing: Button(action: {
                        self.addItemToRow()
                    }){
                        Text("Add")
                    })
  4. Implement the addItemToRow() function, which appends a random integer to the numbers array. Place the function within the ContentView struct, immediately after the body variable's closing brace:
    private func addItemToRow() {
            self.numbers.append(Int.random(in: 0 ..< 100))
        }
  5. For the beauty and aesthetics, add a navigationBarTitle modifier to the end of the list so as to make it display a title at the top of the list:
    .navigationBarTitle("Number List", displayMode: .inline)
  6. The resulting code should be as follows:
    struct ContentView: View {
        @State var numbers = [1,2,3,4]
        var body: some View {
            NavigationView{
                List{
                    ForEach(self.numbers, id:\.self){                  number in
                        Text("\(number)")
                    }
                }.navigationBarTitle("Number List",                displayMode: .inline)
                    .navigationBarItems(trailing:                   Button("Add", action: addItemToRow))
            }
        }
        private func addItemToRow() {
            self.numbers.append(Int.random(in: 0 ..< 100))
        }
    }

    The resulting preview should be as follows:

Figure 2.5 – AddRowToList preview

Figure 2.5 – AddRowToList preview

Run the app live preview and admire the work of your own hands!

How it works…

The array of numbers is declared as a @State variable because we want the view to be refreshed each time the value of the items in the array changes – in this case, each time we add an item to the numbers array.

The .navigationBarTitle("Number List", displayMode: .inline) modifier adds a title to the list using the .inline display mode parameter.

The .navigationBarItems(trailing: Button(…)…) modifier adds a button to the trailing end of the display, which triggers the addItemToRow function when clicked.

The addItemToRow function generates a random number in the range 0–99 and appends it to the numbers array.

Deleting rows from a list

In this section, we will display a list of countries and use a swipe motion to delete items from the list one at a time.

Getting ready

Let's start by creating a SwiftUI app called DeleteRowFromList.

How to do it…

We use the List view's .onDelete(perform: …) modifier to implement list deletion. The process is as follows:

  1. Add a state variable to the ContentView struct called countries. The variable should contain an array of countries:
    @State var countries = ["USA", "Canada",  "England","Cameroon", "South Africa", "Mexico" ,     "Japan", "South Korea"]
  2. Create a List view in the ContentView body that uses a ForEach loop to display the contents of the countries array:
    	 List {
              ForEach(countries, id: \.self) { country in
                  Text(country)
               	}
      	}
  3. Add a .onDelete(perform: self.deleteItem) modifier to the ForEach loop.
  4. Implement the deleteItem() function. The function should be placed below the body variable's closing brace:
    	private func deleteItem(at indexSet: IndexSet){
            self.countries.remove(atOffsets: indexSet)
        }
  5. Optionally, enclose the List view in a navigation view and add a .navigationBarTitle("Countries", displayMode: .inline) modifier to the list. The resulting ContentView struct should be as follows:
    struct ContentView: View {
        @State var countries = ["USA", "Canada",     "England","Cameroon", "South Africa", "Mexico" ,        "Japan", "South Korea"]
        var body: some View {
            NavigationView{
                List {
                    ForEach(countries, id: \.self) {                  country in
                        Text(country)
                    }
                    .onDelete(perform: self.deleteItem)
                }
                .navigationBarTitle("Countries",                displayMode: .inline)
            }
        }
        private func deleteItem(at indexSet: IndexSet){
            self.countries.remove(atOffsets: indexSet)
        }

    Run the canvas review by clicking the play button next to the canvas preview. A swipe from right to left on a row causes a Delete button to appear. Click on the button to delete the row:

Figure 2.6 – DeleteRowFromList preview execution

Figure 2.6 – DeleteRowFromList preview execution

Run the app live preview and admire the work of your own hands!

How it works…

Navigation views and list views were discussed earlier. Only the .onDelete(…) modifier is new. The .onDelete(perform: self.deleteItem) modifier triggers the deleteItem() function when the user swipes from right to left.

The deleteItem(at indexSet: IndexSet) function takes a single parameter, IndexSet, which represents the index of the row to be removed/deleted. The .onDelete() modifier automatically knows to pass the IndexSet parameter to deleteItem(…).

There's more…

Deleting an item from a list view can also be performed by embedding the list in a navigation view and adding an EditButton component.

Editing a list

Implementing the EditButton component in a list is very similar to implementing the delete button in the previous recipe. An edit button offers the user the option to quickly delete items by clicking a minus sign to the left of each list row.

Getting ready

Let's start by creating a SwiftUI app called EditListApp.

How to do it…

We will reuse some of the code from the previous recipe to complete this project. Take the following steps:

  1. Replace the EditListApp app's ContentView struct with the following content from the DeleteRowFromList app:
    struct ContentView: View {
        @State var countries = ["USA", "Canada",     "England","Cameroon", "South Africa", "Mexico" ,        "Japan", "South Korea"]
        var body: some View {
            NavigationView{
                List {
                    ForEach(countries, id: \.self) {                  country in
                        Text(country)
                    }
                    .onDelete(perform: self.deleteItem)
                }
                .navigationBarTitle("Countries",                displayMode: .inline)
            }
        }
        private func deleteItem(at indexSet: IndexSet){
            self.countries.remove(atOffsets: indexSet)
        }
    }
  2. Add a .navigationBarItems(trailing: EditButton()) modifier to the List view, just below the .navigationBarTitle("Countries", displayMode:.inline) modifier.

    Run the preview and click the Edit button at the top-right corner of the screen. Minus (-) signs enclosed in red circles appear to the left of each row:

Figure 2.7 – EditListApp preview execution

Figure 2.7 – EditListApp preview execution

Run the app live preview and admire the work of your own hands!

How it works…

The .navigationBarItems(trailing: EditButton()) modifier adds an edit button to the right corner of the display that, once clicked, creates the view shown in the preceding screenshot. A click on the delete button executes the .onDelete(perform: self.deleteItem) modifier. The modifier then executes the deleteItem function, which removes/deletes the selected row.

There's more…

To move the edit button to the right of the navigation bar, change the modifier to .navigationBarItems(leading: EditButton()).

Moving rows in a list

In this section, we will create an app that implements a list view and allows the user to move/reorganize rows.

Getting ready

Let's start by creating a new SwiftUI app in Xcode called MovingListRows.

How to do it…

To allow users to move rows, we need to add a .onMove(..) modifier to the end of the list view's ForEach loop. We also need to embed the list in a navigation view and add a navigationBarItems modifier that implements an EditButton component. The steps are as follows:

  1. Open ContentView.swift. Within the ContentView struct, add a @State variable in Content called countries that contains an array of countries:
    @State var countries = ["USA", "Canada",   "England","Cameroon", "South Africa", "Mexico" ,    "Japan", "South Korea"]
  2. Replace the Text view in the body with a navigation view:
    NavigationView{
            }
  3. Add a list and a ForEach loop within NavigationView that displays the content of the countries variable:
    List {
         	ForEach(countries, id: \.self) { country in
       		Text(country)
           	}.onMove(perform: moveRow)
          }
  4. Add a .onMove(…) modifier to the ForEach loop that calls the moveRow function:
    	ForEach(countries, id: \.self) { country in
       		Text(country)
           	}.onMove(perform: moveRow)
  5. Add the .navigationBarTitle("Countries", displayMode: .inline) and .navigationBarItems(trailing: EditButton()) modifiers to the end of the List view:
    List {
                    .
    			.
    			.
          }
          .navigationBarTitle("Countries",          isplayMode: .inline)
          .navigationBarItems(trailing: EditButton())
  6. Implement the moveRow function at the end of the body variable's closing brace:
    private func moveRow(source: IndexSet, destination: Int){
            countries.move(fromOffsets: source, toOffset:           destination)
        }
  7. The completed ContentView struct should be as follows:
    struct ContentView: View {
        @State var countries = ["USA", "Canada",      "England","Cameroon", "South Africa", "Mexico" ,         "Japan", "South Korea"]
        var body: some View {
            NavigationView{
                List {
                    ForEach(countries, id: \.self) {                   country in
                        Text(country)
                    }
                    .onMove(perform: moveRow)
                }
                .navigationBarTitle("Countries",                displayMode: .inline)
                .navigationBarItems(trailing: EditButton())
            }
        }
        private func moveRow(source: IndexSet,       destination: Int){
            countries.move(fromOffsets: source,           toOffset: destination)
        }
    }

    Run the application in the canvas, on a simulator, or on a physical device. A click on the Edit button at the top-right corner of the screen displays a hamburger symbol to the right of each row. Click and drag the symbol to move the row on which the country is displayed:

Figure 2.8 – MovingListRows preview when running

Figure 2.8 – MovingListRows preview when running

Run the app live preview and move the rows up or down. Nice work!

How it works…

To move list rows, you need to add the list to a navigation view, add the .onMove(perform:) modifier to the ForEach loop, and add a .navigationBarItems(trailing: EditButton()) modifier to the list.

The moveRow(source: IndexSet, destination: Int) function takes two parameters: the source, an IndexSet argument representing the current index of the item to be moved, and the destination, an integer representing the destination of the row. The .onMove(perform:) modifier automatically passes those arguments to the function.

Adding sections to a list

In this section, we will create an app that implements a static list with sections. The app will display a partial list of countries grouped by continent.

Getting ready

Let's start by creating a new SwiftUI app in Xcode and name it ListWithSections.

How to do it…

We will add section views to our list view. We will then add a few countries to each of the sections. Proceed as follows:

  1. (Optional) open the ContentView.swift file and replace the Text view in the body with a navigation view. Wrapping the list in a navigation view allows you to add a title and navigation items to the view:
    NavigationView {
    }
  2. Add a list and section to the navigation view:
    List {
      	Section(header: Text("North America")){
        		Text("USA")
               Text("Canada")
               Text("Mexico")
               Text("Panama")
               Text("Anguilla")
          }
    }
  3. Add a listStyle(..) modifier to the end of the list to change its style from the default plain style to GroupedListStyle():
    List {
      	.
    	.
    	.
     }
    .listStyle(GroupedListStyle())
    .navigationBarTitle("Continents and Countries",   displayMode: .inline)
  4. (Optional) add a navigationBarTitle(..) modifier to the list, just below the list style. Add this section if you included the navigation view in step 1.
  5. Add more sections representing various continents to the navigation view. The resulting ContentView struct should look as follows:
    struct ContentView: View {
        var body: some View {
            NavigationView{
                List {
                    Section(header: Text("North America")){
                        Text("USA")
                        Text("Canada")
                        Text("Mexico")
                        Text("Panama")
                        Text("Anguilla")
                    }
                    Section(header: Text("Africa")){
                        Text("Nigeria")
                        Text("Ghana")
                        Text("Kenya")
                        Text("Senegal")
                    }
                    Section(header: Text("Europe")){
                        Text("Spain")
                        Text("France")
                        Text("Sweden")
                        Text("Finland")
                        Text("UK")
                    }
                }
            .listStyle(GroupedListStyle())
                .navigationBarTitle("Continents and                Countries", displayMode: .inline)
            }
        }
    }

    The canvas preview should now show a list with sections, as follows:

Figure 2.9 – ListWithSections preview

Figure 2.9 – ListWithSections preview

Good work! Now, run the app live preview and admire the work of your own hands.

How it works…

SwiftUI's sections are used to separate items into groups. In this recipe, we used sections to visually group countries into different continents. Sections can be used with a header, as follows:

Section(header: Text("Europe")){
                    Text("Spain")
                    Text("France")
                    Text("Sweden")
                    Text("Finland")
                    Text("UK")
                }

They can also be used without a header:

Section {
               Text("USA")
               Text("Canada")
               Text("Mexico")
               Text("Panama")
               Text("Anguilla")
         }

When using a section embedded in a list, we can add a .listStyle() modifier to change the styling of the whole list.

Using LazyHStack and LazyVStack (iOS 14+)

SwiftUI 2.0 introduced the LazyHStack and LazyVStack components. These components are used in a similar way to regular HStack and VStack components but offer the advantage of lazy loading. Lazy components are loaded just before the item becomes visible on the device's screen during a device scroll, therefore reducing latency.

We will create an app that uses LazyHStack and LazyVStack and observe how it works.

Getting ready

Let's create a new SwiftUI app called LazyStacks:

  1. Open Xcode and click Create New Project.
  2. In the Choose template window, select iOS and then App.
  3. Click Next.
  4. Enter LazyStacks in the Product Name field and select SwiftUI App from the Life Cycle field.
  5. Click Next and select a location on your computer where the project should be stored.

How to do it…

We will implement a LazyHStack and LazyVStack view within a single SwiftUI view file by embedding both in a VStack component. The steps are as follows:

  1. Click on the ContentView.swift file to view its content in Xcode's editor pane.
  2. Let's create a ListRow SwiftUI view that will have two properties: an ID and a type. ListRow should also print a statement showing what item is currently being initialized:
    struct ListRow: View {
        let id: Int
        let type: String
        init(id: Int, type: String){
            print("Loading \(type) item \(id)")
            self.id = id
            self.type = type
        }
        var body: some View {
            Text("\(type) \(id)").padding()
        }
    }
  3. Replace the initial Text view with VStack:
    VStack {
    }
  4. Add a horizontal scroll view inside the VStack component and use a .frame() modifier to limit the view's height:
    ScrollView(.horizontal){
    }.frame(height: 100, alignment: .center)
  5. Add LazyHStack inside the scroll view with a ForEach view that iterates through the numbers 110000 and displays them using our ListRow view:
    LazyHStack {
         ForEach(1...10000, id:\.self){ item in
           ListRow(id: item, type: "Horizontal")
               }
                    }
  6. Add a second vertical scroll view to VStack with a LazyVStack struct that loops through numbers 110000:
    ScrollView {
      LazyVStack {
        ForEach(1...10000, id:\.self){ item in
          ListRow(id: item, type: "Vertical")
                 }
            }
        }
  7. Now, let's observe lazy loading in action. If the Xcode debug area is not visible, click on View | Debug Area | Show Debug Area:
    Figure 2.10 – Show Debug Area

    Figure 2.10 – Show Debug Area

  8. Select a simulator to use for running the app. The app should look as follows:
    Figure 2.11 – Selecting the simulator from Xcode

    Figure 2.11 – Selecting the simulator from Xcode

  9. Click the play button to run the code in the simulator:
    Figure 2.12 – The LazyStacks app running on the simulator

    Figure 2.12 – The LazyStacks app running on the simulator

  10. Scroll through the items in LazyHStack (located at the top). Observe how the print statements appear in the debug area just before an item is displayed on the screen. Each item is initialized just before it is displayed.
  11. Scroll through the items in LazyVStack. Observe how the print statements appear in the debug area just before an item is displayed.

How it works…

We started this recipe by creating the ListRow view because we wanted to clearly demonstrate the advantage of lazy loading over the regular method where all items get loaded at once. The ListRow view has two properties: an ID and a string. We add a print statement to the init() function so that we can observe when each item gets initialized:

    init(id: Int, type: String){
        print("Loading \(type) item \(id)")
        self.id = id
        self.type = type
    }

The ListRow view body presents a Text view with the ID and type parameters passed to it.

Moving up to the ContentView struct, we replace the initial Text view in the body variable with a VStack component. This allows us to implement both LazyHStack and LazyVStack within the same SwiftUI view.

We implement LazyHStack by first wrapping it in a scroll view, then using a ForEach struct to iterate over the range of values we want to display. For each of those values, a new ListRow view is initialized just before it becomes visible when the user scrolls down:

ScrollView {
  LazyVStack {
   ForEach(1...10000, id:\.self){ item in
    ListRow(id: item, type: "Vertical")
             }
          }
       }

Run the app using a device emulator to view the print statements before each item is initialized. Nothing will be printed if the app is run in live preview mode on Xcode.

There's more…

Try implementing the preceding app using a regular HStack or VStack component and observe the performance difference. The app will be significantly slower since all the rows are initialized at once.

Using LazyHGrid and LazyVGrid (iOS 14+)

Just like lazy stacks, lazy grids use lazy loading to display content on the screen. They initialize only the subset of the items that would soon be displayed on the screen as the user scrolls. SwiftUI 2 introduced the LazyVGrid and LazyHGrid views. Let's implement a lazy grid that displays some text in this recipe.

Getting ready

Create a new SwiftUI iOS project and name it UsingLazyGrids.

How to do it…

We'll implement a LazyVGrid and LazyHGrid view inside a Stack view so as to observe both views in action on a single page. The steps are as follows:

  1. Above the ContentView struct's body variable, let's create an array of GridItem columns. The GridItem struct is used to configure the layout of LazyVGrid:
      let columns = [
        GridItem(.adaptive(minimum: 100))
      ]
  2. Create an array of GridItem rows that define the layout that would be used in LazyHGrid:
      let rows = [
           GridItem(.flexible()),
           GridItem(.flexible()),
           GridItem(.flexible())
      ]
  3. Create an array of colors. This will be used for styling some items in our view:
    let colors: [Color] = [.green,.red, .yellow,.blue]
  4. Replace the initial Text view in the body view with a VStack component and a scroll view.
  5. Within the scroll view, add a LazyVGrid view and a ForEach struct that iterates over the numbers 1999 and displays the number in a Text view:
     VStack {
       ScrollView {
        LazyVGrid(columns: columns, spacing:20) {
         ForEach(1...999, id:\.self){ index in
          Text("Item \(index)")
         }
        }
       }
     }
  6. The resulting view displays the numbers in a grid, but the content looks very bland. Let's add some zest by styling the text.
  7. Add a padding() modifier, a background modifier that uses the value of the current index to pick a color from our color array, and the clipshape() modifier to give each Text view a capsule shape:
    …
    ForEach(1...999, id:\.self){ index in
             Text("Item \(index)")
             .padding(EdgeInsets(top: 30, leading: 15,             bottom: 30, trailing: 15))
             .background(colors[index % colors.count])
              .clipShape(Capsule())
              }
    …
  8. Now, let's add a scroll view and LazyHStack. You will notice that everything else is the same as the LazyVGrid view except for the column parameter that's changed to a row parameter:
    VStack {
             …
              ScrollView(.horizontal) {
               LazyHGrid(rows: rows, spacing:20) {
                ForEach(1...999, id:\.self){ index in
                 Text("Item \(index)")
                      .foregroundColor(.white)
                      .padding(EdgeInsets(top: 30, leading:                     15, bottom: 30, trailing: 15))
                      .background(colors[index % colors.                     count])
                      .clipShape(Capsule())
                        }
                    }
                }
            }

    The resulting preview should look as follows:

Figure 2.13 – The UsingLazyStacks app

Figure 2.13 – The UsingLazyStacks app

Run the app in the preview and vertically scroll through LazyVGrid and horizontally scroll through LazyHGrid. Observe how smoothly the scrolling occurs despite the fact that our data source contains close to 2,000 elements. Scrolling stays responsive because all our content is lazily loaded.

How it works…

One of the fundamental concepts of using lazy grids involves understanding how to define the LazyVGrid columns or the LazyHGrid rows. The LazyVGrid column variable was defined as an array containing a single GridItem component but causes three rows to be displayed. GridItem(.adaptive(minimum: 80)) tells SwiftUI to use at least 80 units of width for each item and place as many items as it can along the same row. Thus, the number of items displayed on a row may increase when the device is changed from portrait to landscape orientation, and vice versa.

GridItem(.flexible()), on the other hand, fills up each row as much as possible:

let rows = [
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible())
    ]

Adding three GridItem(.flexible()) components divides the available space into three equal rows for data display. Remove or add more GridItem(.flexible()) components to the row array and observe how the number of rows decreases or increases.

We provide two parameters to our lazy grids: a columns/rows parameter that specifies the layout of the grid and a spacing parameter that defines the spacing between the grid and the next item in the parent view.

Using ScrollViewReader (iOS 14+)

ScrollViewReader can be used to programmatically scroll to a different section of a list that might not be currently visible. In this recipe, we will create an app that displays a list of characters from A to L. The app will also have a button at the top for programmatically scrolling to the last element in the list and a button at the bottom for programmatically scrolling to an element in the middle of the list.

Getting ready

Create a new SwiftUI app using the UIKit App Delegate life cycle:

Figure 2.14 – UIKit App Delegate in Xcode

Figure 2.14 – UIKit App Delegate in Xcode

Name the app UsingScrollViewReader.

How to do it…

We will start by creating an array of structs with a name and an ID. The array will be used to display SF symbols for the characters A–L. We will then proceed to implement ScrollViewReader and programmatically move to the top or the bottom of the list.

The steps are as follows:

  1. Create a struct called ImageStore, just above the ContentView_Previews struct. The struct should implement the Identifiable protocol:
    struct ImageStore: Identifiable {
        var name: String
        var id: Int
    }
  2. Within the ContentView struct, just before the body variable, declare an array called imageNames. Initialize the array with ImageStore structs whose name parameters represent the letters A–Q from SF Symbols:
        let imageNames = [
            ImageStore(name:"a.circle.fill",id:0),
            ImageStore(name:"b.circle.fill",id:1),
            ImageStore(name:"c.circle.fill",id:2),
            ImageStore(name:"d.circle.fill",id:3),
            ImageStore(name:"e.circle.fill",id:4),
            ImageStore(name:"f.circle.fill",id:5),
            ImageStore(name:"g.circle.fill",id:6),
            ImageStore(name:"h.circle.fill",id:7),
            ImageStore(name:"i.circle.fill",id:8),
            ImageStore(name:"j.circle.fill",id:9),
            ImageStore(name:"k.circle.fill",id:10),
            ImageStore(name:"l.circle.fill",id:11),
            ImageStore(name:"m.circle.fill",id:12),
            ImageStore(name:"n.circle.fill",id:13),
            ImageStore(name:"o.circle.fill",id:14),
            ImageStore(name:"p.circle.fill",id:15),
            ImageStore(name:"q.circle.fill",id:16),
        ]
  3. Replace the TextView component in the body variable with a ScrollView component, ScrollViewReader, and a Button component to navigate to the letter Q in the list:
    ScrollView {
         ScrollViewReader { value in
         Button("Go to letter Q") {
         value.scrollTo(16)
               }
            }         
        }
  4. Now use a ForEach struct to iterate over the imageNames array and display its content using the SwiftUI's Image struct:
     ForEach(imageNames){ image in
       Image(systemName: image.name)
         .id(image.id)
         .font(.largeTitle)
         .foregroundColor(Color.yellow)
         .frame(width: 90, height: 90)
         .background(Color.blue)
         .padding()
       }
  5. Now, add another button at the bottom that causes the list to scroll back to the top:
    Button("Go back to A") {
            value.scrollTo(0)
       }
  6. The app should be able to run now, but let's add some padding and background to the bottom and top buttons to improve their appearance:
    Button("Go to letter Q") {
           value.scrollTo(0)
          }
          .padding()
          .background(Color.yellow)
    	Button("Go to G") {
            value.scrollTo(6, anchor: .bottom)
          }
           .padding()
           .background(Color.yellow)

    The resulting app preview should look as follows:

Figure 2.15 – The UsingScrollViewReader app

Figure 2.15 – The UsingScrollViewReader app

Run the app in Xcode live preview and tap the button at the top to programmatically scroll down to the letter Q.

Scroll to the bottom of the view and tap the button to scroll up to the view where the letter G is at the bottom of the visible area.

How it works…

We start this recipe by creating the ImageStore struct that defines the properties of each image we want to display:

struct ImageStore: Identifiable {
    var name: String
    var id: Int
}

The id parameter is required for ScrollViewReader as a reference for the location to scroll to, just like a house address provides the final destination for driving. By making the struct extend the Identifiable protocol, we are able to iterate over the imageNames array without specifying an id parameter to the ForEach struct:

ForEach(imageNames){ image in
                    Image(systemName: image.name)
				…
                }

ScrollViewReader should be embedded inside a scroll view. This provides a scrollTo() method that can be used to programmatically scroll to the item whose index is specified in the method:

ScrollViewReader { value in
                Button("Go to letter Q") {
                    value.scrollTo(16)
                }
			…
}

The scrollTo() method also has an anchor parameter that is used to specify the position of the item we are scrolling to; for example, scrollTo(6, anchor: .top), in this case, causes the app to scroll until the ImageStore item with ID 6 at the bottom of the view.

Using expanding lists (iOS 14+)

Expanding lists can be used to display hierarchical structures within a list. Each list item can be expanded to view its contents. The expanding ability is achieved by creating a struct that holds some information and an optional array of items of the same type as the struct itself. Let's examine how expanding lists work by creating an app that displays the contents of a backpack.

Getting ready

Create a new SwiftUI app and name it UsingExpandingLists.

How to do it…

We start by creating the Backpack struct that describes the properties of the data we want to display. We'll then create a number of Backpack constants and display the hierarchical information using a List view containing a children property.

The steps are as follows:

  1. At the bottom of the ContentView.swift file, define a Backpack struct that has an id, name, icon, and content property. The content property's type should be an optional array of Backpack structs:
    struct Backpack: Identifiable {
        let id = UUID()
        let name: String
        let icon: String
        var content: [Backpack]?
    }
  2. Below the Backpack struct declaration, create three variables: two currency types and an array of currencies:
    let dollar = Backpack(name: "Dollar", icon: "dollarsign.   circle")
    let yen = Backpack(name: "Yen",icon: "yensign.circle")
    let currencies = Backpack(name: "Currencies", icon:    "coloncurrencysign.circle", content: [dollar, yen])
  3. Create a pencil, hammer, paperclip, and glass constant:
    let pencil = Backpack(name: "Pencil",icon: "pencil.  circle")
    let hammer = Backpack(name: "Hammer",icon: "hammer")
    let paperClip = Backpack(name: "Paperclip",icon:   "paperclip")
    let glass = Backpack(name: "Magnifying glass",   icon: "magnifyingglass")
  4. Create a bin Backpack constant that contains paperclip and glass, as well as a tool constant that holds pencil, hammer, and bin:
    let bin  = Backpack(name: "Bin", icon: "arrow.up.bin",  content: [paperClip, glass])
    let tools = Backpack(name: "Tools", icon: "folder",   content: [pencil, hammer,bin])
  5. Going back to the ContentView struct, add an instance property; items, which contains an array of two items, the currencies and tools constants defined earlier:
    struct ContentView: View {
        let items = [currencies,tools]
        …
    }
  6. Within the body variable, replace the Text view with a List view that displays the content of the items array:
        var body: some View {
            List(items, children: \.content){ row in
                Image(systemName: row.icon)
                Text(row.name)
            }
        }

    The resulting Xcode live preview should look as follows when expanded:

Figure 2.16 – UsingExpandingLists

Figure 2.16 – Using expanding lists

Run the Xcode live preview and click on the arrows to expand and collapse the views.

How it works…

We start by creating a struct of the proper format for expanding lists. Expanding lists require one of the struct properties to be an optional array of the same type as the struct itself. Our Backpack content property holds an optional array of Backpack items:

struct Backpack: Identifiable {
    let id = UUID()
    let name: String
    let icon: String
    var content: [Backpack]?
}

The UUID() function generates a random identifier and stores it in the id property. We can manually provide the name, icon, and content variables for the items we add to the backpack.

We create our first hierarchical structure by creating the Dollar and Yen variables:

let dollar = Backpack(name: "Dollar", icon: "dollarsign.  circle")
let yen = Backpack(name: "Yen",icon: "yensign.circle")

Observe that no content property has been provided for both variables. This is possible because the content is an optional parameter.

We then create a currencies constant that that has name and icon. The Dollar and Yen variables created earlier are added to its content array.

We use a similar composition to add elements to our tool constant.

After setting up the data we want to display, we create an item property in our ContentView struct that holds an array of Backpack constants created earlier:

let items = [currencies,tools]

Finally, we replace the Text view in the ContentView body with a List view that iterates over the items. The list is made expandable by adding the children parameter, which expects an array of the same time as the struct passed to the List view.

There's more…

The tree structure used for expandable lists can also be generated on a single line, as follows:

let tools = Backpack(name: "Tools", icon: "folder", content:
   [Backpack(name: "Pencil",icon: "pencil.circle"),
    Backpack(name: "Hammer",icon: "hammer"),
    Backpack(name: "Bin", icon: "arrow.up.bin", content:
        [Backpack(name: "Paperclip",icon: "paperclip"),
         Backpack(name: "Magnifying glass", icon:           "magnifyingglass")
           ])
       ])

The SwiftUI List view provides out-of-the-box support for OutlineGroup in iOS 14. OutlineGroup computes views and disclosure groups on demand from an underlying collection.

See also

Refer to the WWDC20 video on stacks, grids, and outlines at https://developer.apple.com/videos/play/wwdc2020/10031/.

Refer to the Apple documentation on OutlineGroup at https://developer.apple.com/documentation/swiftui/outlinegroup.

Using disclosure groups to hide and show content (iOS 14+)

DisclosureGroup is a view used to show or hide content based on the state of a disclosure control. It takes two parameters: a label to identify its content and a binding to control whether its content is shown or hidden. Let's take a closer look at how it works by creating an app that shows and hides content in a disclosure group.

Getting ready

Create a new SwiftUI project and name it UsingDisclosureGroup.

How to do it…

We will create an app the uses DisclosureGroup views to reveal some planets in our solar system, continents on the Earth, and some surprise text. The steps are as follows:

  1. Below the ContentView struct, add a state property called showplanets:
    @State private var showplanets = true
  2. Replace the Text view in the body variable with a DisclosureGroup view that displays some planets:
     DisclosureGroup("Planets", isExpanded: $showplanets){
         Text("Mercury")
         Text("Venus") 
    }
  3. Review the result in Xcode's live preview, then nest another DisclosureGroup view for planet Earth. The group should contain the list of Earth's continents:
      DisclosureGroup("Planets", isExpanded: $showplanets){
    	…
           DisclosureGroup("Earth"){
                    Text("North America")
                    Text("South America")
                    Text("Europe")
                    Text("Africa")
                    Text("Asia")
                    Text("Antarctica")
                    Text("Oceania")
                }
            }
  4. Let's add another DisclosureGroup view using a different way of defining them. Since the body variable can't display two views, let's embed our parent DisclosureGroup view in a VStack component. Hold down the key and click on the parent DisclosureGroup view and select Embed in VStack from the list of actions.
  5. Below our parent DisclosureGroup view, add another one that reveals surprise text when clicked:
    VStack {
        DisclosureGroup("Planets", isExpanded: $showplanets){
             Text("Mercury")
             Text("Venus")
                    
             DisclosureGroup("Earth"){
                Text("North America")
                Text("South America")
                Text("Europe")
                Text("Africa")
                Text("Asia")
                Text("Antarctica")
                Text("Oceania")
             }
          }
          DisclosureGroup{
            Text("Surprise! This is an alternative                  way of using DisclosureGroup")
          } label : {
              Label("Tap to reveal", systemImage: "cube.box")
                    .font(.system(size:25, design: .rounded))
                    .foregroundColor(.blue)
                }
          }

    The resulting preview should be as follows:

Figure 2.17 – The UsingDisclosureGroup app

Figure 2.17 – The UsingDisclosureGroup app

Run the Xcode live preview and click on the arrows to expand and collapse the views.

How it works…

Our initial DisclosureGroup view presents a list of planets. By passing in a binding, we are able to read the state change and know whether the DisclosureGroup view is in an open or closed state:

DisclosureGroup("Planets", isExpanded: $showplanets){
     Text("Mercury")
     Text("Venus") 
} 

We can also use DisclosureGroup views without bindings, depending solely on the default UI:

DisclosureGroup("Earth"){
    Text("North America")
    Text("South America")
     …
 }

Lastly, we used the new Swift 5.3 closure syntax to separate the Text and Label portions into two separate views. This allows more customization of the Label portion:

DisclosureGroup{
  Text("Surprise! This is an alternative way of using      DisclosureGroup")
  } label : {
      Label("Tap to reveal", systemImage: "cube.box")
           .font(.system(size:25, design: .rounded))
           .foregroundColor(.blue)
  }

DisclosureGroup views are very versatile as they can be nested and used to display content in a hierarchical way.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Apply the declarative programming paradigm for building cross-platform UIs for Apple devices
  • Learn to integrate UIKit, Core Data, Sign in with Apple, and Firebase with SwiftUI
  • Adopt the new SwiftUI 2.0 features to build visually appealing UIs at speed

Description

SwiftUI is an innovative and simple way to build beautiful user interfaces (UIs) for all Apple platforms, right from iOS and macOS through to watchOS and tvOS, using the Swift programming language. In this recipe-based book, you’ll work with SwiftUI and explore a range of essential techniques and concepts that will help you through the development process. The recipes cover the foundations of SwiftUI as well as the new SwiftUI 2.0 features introduced in iOS 14. Other recipes will help you to make some of the new SwiftUI 2.0 components backward-compatible with iOS 13, such as the Map View or the Sign in with Apple View. The cookbook begins by explaining how to use basic SwiftUI components. Then, you’ll learn the core concepts of UI development such as Views, Controls, Lists, and ScrollViews using practical implementation in Swift. By learning drawings, built-in shapes, and adding animations and transitions, you’ll discover how to add useful features to the SwiftUI. When you’re ready, you’ll understand how to integrate SwiftUI with exciting new components in the Apple development ecosystem, such as Combine for managing events and Core Data for managing app data. Finally, you’ll write iOS, macOS, and watchOS apps while sharing the same SwiftUI codebase. By the end of this SwiftUI book, you'll have discovered a range of simple, direct solutions to common problems found in building SwiftUI apps.

Who is this book for?

This book is for mobile developers who want to learn SwiftUI as well as experienced iOS developers transitioning from UIKit to SwiftUI. The book assumes knowledge of the Swift programming language. Knowledge of object-oriented design and data structures is useful but not necessary.

What you will learn

  • Explore various layout presentations in SwiftUI such as HStack, VStack, LazyHStack, and LazyVGrid
  • Create a cross-platform app for iOS, macOS, and watchOS
  • Get up to speed with drawings in SwiftUI using built-in shapes, custom paths, and polygons
  • Discover modern animation and transition techniques in SwiftUI
  • Add user authentication using Firebase and Sign in with Apple
  • Handle data requests in your app using Core Data
  • Solve the most common SwiftUI problems, such as integrating a MapKit map, unit testing, snapshot testing, and previewing layouts

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Oct 19, 2020
Length: 614 pages
Edition : 1st
Language : English
ISBN-13 : 9781838981860
Vendor :
Apple
Category :
Languages :
Tools :

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing

Product Details

Publication date : Oct 19, 2020
Length: 614 pages
Edition : 1st
Language : English
ISBN-13 : 9781838981860
Vendor :
Apple
Category :
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just Can$6 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just Can$6 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total Can$ 189.97
iOS 14 Programming for Beginners
Can$69.99
SwiftUI Projects
Can$49.99
SwiftUI Cookbook
Can$69.99
Total Can$ 189.97 Stars icon
Banner background image

Table of Contents

14 Chapters
Chapter 1: Using the Basic SwiftUI Views and Controls Chevron down icon Chevron up icon
Chapter 2: Going Beyond the Single Component with Lists and Scroll Views Chevron down icon Chevron up icon
Chapter 3: Viewing while Building with SwiftUI Preview Chevron down icon Chevron up icon
Chapter 4: Creating New Components and Grouping Views in Container Views Chevron down icon Chevron up icon
Chapter 5: Presenting Extra Information to the User Chevron down icon Chevron up icon
Chapter 6: Drawing with SwiftUI Chevron down icon Chevron up icon
Chapter 7: Animating with SwiftUI Chevron down icon Chevron up icon
Chapter 8: Driving SwiftUI with Data Chevron down icon Chevron up icon
Chapter 9: Driving SwiftUI with Combine Chevron down icon Chevron up icon
Chapter 10: Handling Authentication and Firebase with SwiftUI Chevron down icon Chevron up icon
Chapter 11: Handling Core Data in SwiftUI Chevron down icon Chevron up icon
Chapter 12: Cross-Platform SwiftUI Chevron down icon Chevron up icon
Chapter 13: SwiftUI Tips and Tricks Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.8
(10 Ratings)
5 star 90%
4 star 0%
3 star 10%
2 star 0%
1 star 0%
Filter icon Filter
Top Reviews

Filter reviews by




L. Stone Jan 31, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I've been studying Swift 5 and SwiftUI for a little while now, as a hobby, mostly using Udemy tutorials and a couple of basic books. This particular book, however, is helping me "put it all together" in my mind better than anything I've read or watched so far. The author takes a sort of layered, cyclical approach to topics: you'll see something show up early in the book, with little comment but it's easy to see what it's doing, so when you get to the chapter devoted to that thing you're not starting from total scratch. You also revisit old topics when learning new topics, so things can sink in better. So far I'm on page 165, and can hardly wait to go through the drawing and animation chapters (pp. 198-326). Several chapters follow for working with Combine and Firebase and so on, though I probably won't get to those for several months yet.
Amazon Verified review Amazon
Amazon Customer Mar 11, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Perfect for my needs!
Amazon Verified review Amazon
Frank Linux Mar 23, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Good variety of common topics. As mentioned in the advertising, the book works well for developers transitioning from UIKit to SwiftUI.
Amazon Verified review Amazon
Amazon Customer Dec 17, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I like this book a lot. This book helps me get up and running pretty fast with SwiftUI. Highly recommend.
Amazon Verified review Amazon
Nicholas Jan 13, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Hello, I am an iOS developer so I have experience working in the traditional UIKit framework. Before I talk about the many great things in this book (theres a bunch!) I want to first discuss who its for. I attached an excerpt from the book on who this is for because if you dont know anything about swift it might make the topics within harder to grasp. From what I read so far you dont need mastery of the Swift language, just a basic understanding should get you through it.SwiftUI has a new way of implementing stack views and this book begins by covering that topic. There aren't really storyboards the way you are used to seeing them in xcode which may come as a shock to some users, unless you build your user interface programmatically already. Each chapter will explore new features such as Scroll Views, Container Views, and Alerts.It has a dedicated chapter on Core Data which I found an interesting readThe eBook version has color illustrations, which I appreciate very much and I found the example code presented within the book to be relevant to the topics being covered.If you follow along with the examples in this book you will build a tic-tac-toe game, a cute little progress ring, bar graphs, pie chart, and a lot more.I found swiftUI to be a really unique coding experience and I feel great having this book as a companion.*One last note, you will also need a semi beefy computer to fully utilize the preview mode that shows you what you're coding as you code. Its a great feature but I have seen it bog down my less powerful mac.Overall this book is 5 stars and will set you up right.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is included in a Packt subscription? Chevron down icon Chevron up icon

A subscription provides you with full access to view all Packt and licnesed content online, this includes exclusive access to Early Access titles. Depending on the tier chosen you can also earn credits and discounts to use for owning content

How can I cancel my subscription? Chevron down icon Chevron up icon

To cancel your subscription with us simply go to the account page - found in the top right of the page or at https://subscription.packtpub.com/my-account/subscription - From here you will see the ‘cancel subscription’ button in the grey box with your subscription information in.

What are credits? Chevron down icon Chevron up icon

Credits can be earned from reading 40 section of any title within the payment cycle - a month starting from the day of subscription payment. You also earn a Credit every month if you subscribe to our annual or 18 month plans. Credits can be used to buy books DRM free, the same way that you would pay for a book. Your credits can be found in the subscription homepage - subscription.packtpub.com - clicking on ‘the my’ library dropdown and selecting ‘credits’.

What happens if an Early Access Course is cancelled? Chevron down icon Chevron up icon

Projects are rarely cancelled, but sometimes it's unavoidable. If an Early Access course is cancelled or excessively delayed, you can exchange your purchase for another course. For further details, please contact us here.

Where can I send feedback about an Early Access title? Chevron down icon Chevron up icon

If you have any feedback about the product you're reading, or Early Access in general, then please fill out a contact form here and we'll make sure the feedback gets to the right team. 

Can I download the code files for Early Access titles? Chevron down icon Chevron up icon

We try to ensure that all books in Early Access have code available to use, download, and fork on GitHub. This helps us be more agile in the development of the book, and helps keep the often changing code base of new versions and new technologies as up to date as possible. Unfortunately, however, there will be rare cases when it is not possible for us to have downloadable code samples available until publication.

When we publish the book, the code files will also be available to download from the Packt website.

How accurate is the publication date? Chevron down icon Chevron up icon

The publication date is as accurate as we can be at any point in the project. Unfortunately, delays can happen. Often those delays are out of our control, such as changes to the technology code base or delays in the tech release. We do our best to give you an accurate estimate of the publication date at any given time, and as more chapters are delivered, the more accurate the delivery date will become.

How will I know when new chapters are ready? Chevron down icon Chevron up icon

We'll let you know every time there has been an update to a course that you've bought in Early Access. You'll get an email to let you know there has been a new chapter, or a change to a previous chapter. The new chapters are automatically added to your account, so you can also check back there any time you're ready and download or read them online.

I am a Packt subscriber, do I get Early Access? Chevron down icon Chevron up icon

Yes, all Early Access content is fully available through your subscription. You will need to have a paid for or active trial subscription in order to access all titles.

How is Early Access delivered? Chevron down icon Chevron up icon

Early Access is currently only available as a PDF or through our online reader. As we make changes or add new chapters, the files in your Packt account will be updated so you can download them again or view them online immediately.

How do I buy Early Access content? Chevron down icon Chevron up icon

Early Access is a way of us getting our content to you quicker, but the method of buying the Early Access course is still the same. Just find the course you want to buy, go through the check-out steps, and you’ll get a confirmation email from us with information and a link to the relevant Early Access courses.

What is Early Access? Chevron down icon Chevron up icon

Keeping up to date with the latest technology is difficult; new versions, new frameworks, new techniques. This feature gives you a head-start to our content, as it's being created. With Early Access you'll receive each chapter as it's written, and get regular updates throughout the product's development, as well as the final course as soon as it's ready.We created Early Access as a means of giving you the information you need, as soon as it's available. As we go through the process of developing a course, 99% of it can be ready but we can't publish until that last 1% falls in to place. Early Access helps to unlock the potential of our content early, to help you start your learning when you need it most. You not only get access to every chapter as it's delivered, edited, and updated, but you'll also get the finalized, DRM-free product to download in any format you want when it's published. As a member of Packt, you'll also be eligible for our exclusive offers, including a free course every day, and discounts on new and popular titles.