Using lists in SwiftUI
A list is used in SwiftUI to present rows of data in a single column. This was previously done using UITableView in UIKit. Use of the list container in SwiftUI simplifies the amount of code to create a simple list of items as well as allowing custom layout of the rows in the list.
Hard coded list
Start with a simple List of the colors of the rainbow. The following code embeds a number of Text views in a List. The image shows the difference between this and embedding the text views in a VStack. In the List, each text view has its own row with a horizontal line separator between them.
1struct HardCodedListView: View {
2 var body: some View {
3 List {
4 Text("Red")
5 Text("Orange")
6 Text("Yellow")
7 Text("Green")
8 Text("Blue")
9 Text("Indigo")
10 Text("Violet")
11 }
12 }
13}
Text displayed using VStack rather than a list
List of text data displayed using a list
Display a list from array of strings
It is more common to create a list of views from data in a model or generated
elswhere in the app. The following code uses a list of colors in an array. SwiftUI
requires that each of the items in the List has a unique identifier, so that SwiftUI
is able to update the UI automatically when items in the list change. The use of id: \.self
as the identifier means the whole object, which really means a unique hash of
that object. This works for the list of String objects because string conforms to
Hashable protocol.
Two methods of iterating over the items in the list are shown below. The first
iterates over the list using a variable for each item in the list, the second uses
the shorthand $0
for the first parameter of the closure.
1struct TextListView: View {
2 private let colors = ["Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet"]
3
4 var body: some View {
5 VStack {
6 List(self.colors, id: \.self) { col in
7 Text(col)
8 }
9
10 List(colors, id: \.self) {
11 Text($0)
12 }
13 }
14
15 }
16}
Populating views in a list from an array of strings
Identifiable Structures
In most Apps the items in the list will be more than simple strings. The following code creates a structure that conforms to the Identifiable protocol and this ID is used to uniquely identify the items in the list.
1struct StructListView: View {
2 struct MyColor: Identifiable {
3 let id = UUID()
4 let name: String
5 }
6
7 private var colors = [
8 MyColor(name: "Red"),
9 MyColor(name: "Orange"),
10 MyColor(name: "Yellow"),
11 MyColor(name: "Green"),
12 MyColor(name: "Blue"),
13 MyColor(name: "Indigo"),
14 MyColor(name: "Violet")
15 ]
16
17 var body: some View {
18 List(colors) {
19 Text($0.name)
20 }
21 }
22}
List of views with struct conforming to Identifiable
More data per row
It may seem overly-complicated to create a struct for just one string value as above, but this struct can be more complicated with multiple fields. The layout of each of the rows can be modified to display part or all of the data in the struct. The following code adds a description field and displays the first portion of the description in each row of the list. A HStack is used to layout the name beside the description on each row.
1struct MyColor: Identifiable {
2 let id = UUID()
3 let name: String
4 let description: String
5}
1var body: some View {
2 List(self.colors) { col in
3 HStack {
4 Text(col.name)
5 .font(.title)
6 .fontWeight(.bold)
7 Spacer()
8 Text(col.description)
9 .frame(width: 200, alignment: .leading)
10 .lineLimit(3)
11 }
12 }
13}
List of views with multiple data per row
Separate the row layout
The final step is to separate row layout into a separate view so that it can be modified independently of the list view. The color is also added to the MyColor struct.
1struct FinalListView: View {
2 private var colors = [
3 MyColor(name: "Red",
4 col: Color(.red),
5 description: "Red is the color at the end of the visible spectrum of light. It has a dominant wavelength of approximately 625–740 nanometres. It is a primary color in the RGB color model and the CMYK color model, and is the complementary color of cyan. Reds range from the brilliant yellow-tinged scarlet and vermillion to bluish-red crimson, and vary in shade from the pale red pink to the dark red burgundy."),
6 MyColor(name: "Orange",
7 col: Color(.orange),
8 description: "Orange is the colour between yellow and red on the spectrum of visible light. It has a dominant wavelength of approximately 585-620 nanometres. In painting and traditional colour theory, it is a secondary colour of pigments, created by mixing yellow and red. In the RGB color model, it is a tertiary colour. It is named after the fruit of the same name."),
9 MyColor(name: "Yellow",
10 col: .yellow,
11 description: "Yellow is the color between orange and green on the spectrum of visible light. It has a dominant wavelength of approximately 570–590 nanometres. It is a primary color in subtractive color systems, used in painting or color printing. In the RGB color model, used to create colors on television and computer screens, yellow is a secondary color made by combining red and green at equal intensity. Carotenoids give the characteristic yellow color to autumn leaves, corn, canaries, daffodils, and lemons, as well as egg yolks, buttercups, and bananas. Sunlight has a slight yellowish hue when the Sun is near the horizon, due to atmospheric scattering of shorter wavelengths (green, blue, and violet)."),
12 MyColor(name: "Green",
13 col: .green,
14 description: "Green is the color between blue and yellow on the visible spectrum. It has a dominant wavelength of approximately 495–570 nanometres. In subtractive color systems, used in painting and color printing, it is created by a combination of yellow and blue, or yellow and cyan; in the RGB color model, used on television and computer screens, it is one of the additive primary colors, along with red and blue, which are mixed in different combinations to create all other colors. By far the largest contributor to green in nature is chlorophyll, the chemical by which plants photosynthesize and convert sunlight into chemical energy. Many creatures have adapted to their green environments by taking on a green hue themselves as camouflage."),
15 MyColor(name: "Blue",
16 col: .blue,
17 description: "Blue is one of the three primary colours of pigments in painting and traditional colour theory, as well as in the RGB colour model. It lies between violet and green on the spectrum of visible light. It has a dominant wavelength of approximately 450-495 nanometres. Most blues contain a slight mixture of other colours; azure contains some green, while ultramarine contains some violet. The clear daytime sky and the deep sea appear blue because of an optical effect known as Rayleigh scattering."),
18 MyColor(name: "Indigo",
19 col: Color(red: 75/255, green: 0/255, blue: 130/255),
20 description: "Indigo is a deep and rich color close to the color wheel blue, as well as to some variants of ultramarine, based on the ancient dye of the same name. The word indigo comes from the Latin for Indian as the dye was originally exported to Europe from India. It is traditionally regarded as a color in the visible spectrum, as well as one of the seven colors of the rainbow: the color between blue and violet; however, sources differ as to its actual position in the electromagnetic spectrum."),
21 MyColor(name: "Violet",
22 col: Color(red: 159/255, green: 0/255, blue: 255/255),
23 description: "Violet is the color of light at the short wavelength end of the visible spectrum, between blue and invisible ultraviolet. It is one of the seven colors that Isaac Newton labeled when dividing the spectrum of visible light in 1672. Violet light has a wavelength between approximately 380-450 nanometers. The color's name is derived from the violet flower.")
24 ]
25
26 var body: some View {
27 List(self.colors) { col in
28 RowView(colr: col)
29 }
30 }
31}
1struct MyColor: Identifiable {
2 let id = UUID()
3 let name: String
4 let col: Color
5 let description: String
6}
7
8struct RowView: View {
9 var colr: MyColor
10
11 var body: some View {
12 VStack {
13 RoundedRectangle(cornerRadius: 20)
14 .fill(colr.col)
15 .frame(idealWidth: 200, maxWidth: .infinity, minHeight: 5, idealHeight: 5, maxHeight: 5, alignment: .center)
16 HStack {
17 Text(colr.name)
18 .font(.title)
19 .fontWeight(.bold)
20 Spacer()
21 RoundedRectangle(cornerRadius: 20)
22 .fill(colr.col)
23 .frame(idealWidth: 5, maxWidth: 5, minHeight: 50, idealHeight: 50, maxHeight: .infinity, alignment: .leading)
24 Text(colr.description)
25 .frame(width: 200, alignment: .leading)
26 .lineLimit(3)
27 }
28 }
29 }
30}
List of views with layout for row defined separately
Conclusion
Lists are used in SwiftUI to present rows of data in a single column similar to how UITableViews are used in UIKit. It is much easier to use the list container in SwiftUI. The list can be bound to an array of objects in a data model as long as those objects conform to the Identifiable protocol. It is required that each item in a list has a unique identifier so that SwiftUI can respond when items are modified. The layout for each row in the list can be separated into its own view making it easier to modify and maintain.