Easy to understand UITableview Implementation in SwiftUI

Hey there!! The agenda of this post is to get you on the speed with SwiftUI and I have chosen the most versatile UI component in iOS app world the UITableView.

Today we will be making a UITableView with a custom cell and I will try to keep it as simple as possible.Let’s begin

Creating a SwiftUI Application

Creating a SwiftUI project
  • Select interface to be SwiftUI
  • Select SwiftUI App as Life Cycle
  • Select language as Objective-c (You believe me?) Swift, The language is Swift

The image above shows the basic project configuration. Now open the project

What we are making

We are going to make a simple list of cute animals. This app will display a list of cute animals with their name and image. The table view will be driven by a data source. For now, we are keeping things local. You need to go to iemoji and download following animal images

  • Goat (its cute for many, not me but many)
  • Deer
  • Cat
  • Dog

Add the images in XCAssets and you can keep the scale universal for this tutorial

Introduction to basic

If you open the SwiftUITableviewApp.swift file you will see it contains the following code

struct SwiftUITableviewApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView() // this calls ContentView in file ContentView.swift
        }
    }
}

This is the app launch point for simplicity we will be working only in ContentView.swift.

Creating Tableview

We will create an Animal struct that will conform to Identifiable as shown in the code below

struct Animal:Identifiable { // its a requirement for List datasource
    var id: Int
    var name: String
    var image: String
}

Now we will create multiple instances of this struct and store it in an animalList array

let animalList = [
    Animal(id: 1, name: "goat", image: "goat"),
    Animal(id: 1, name: "dog", image: "dog"),
    Animal(id: 1, name: "deer", image: "deer"),
    Animal(id: 1, name: "cat", image: "cat"),
]

Now before we create our row I would like to click on the resume button in the preview section. You should see a Hello World screen this is because of the code

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Lets create a simple row and show it on screen directly without list.

struct cell: View {
    var body: some View {
        HStack { // HStack means horizontal stack and we have stacked image and text component horizontally
            Text("goat")
            Image("goat")
        }
    }
}

after creating a simple row we will call it in ContentView to show on screen

struct ContentView: View {
    var body: some View {
        Cell()
    }
}

Now once you click resume on the preview pannel you will be presented with our magnificent goat

Yuck!!!!

Its not looking that presentable. So we will be adding some spacer to add space between our goat and text and then we will resize the goat follow on in code.

struct Cell: View {
    var body: some View {
        HStack {
            Text("goat")
            Spacer() // will add space between text and goat like pring
            Image("goat")
                .resizable()
                .aspectRatio(contentMode:.fit) 
                .frame(maxWidth:40) // setting max width
        }
    }
}

Now the image looks less goatish. At this point, we will not worry about the leading and trailing spaces as our table view will take care of it.

As you keen-eyed people have already observed that the cell we have created is showing static data and is not a part of any table view, In the next step we will create that

// make the cell dynamic
struct Cell: View {
    var animal:Animal. // added a animal type property
    var body: some View {
        HStack {
            Text(animal.name) // used property to get name 
        Spacer()
            Image(animal.image) // used property to get image name
            .resizable()
            .aspectRatio(contentMode:.fit)
            .frame(maxWidth:40)
        }
    }
}

At this point, you will start getting errors in content view but don’t worry about it lets create our table view list as we call them in swift

struct Mytable: View {
    var animals: [Animal] // data source animal array
    var body : some View {
        List(animals) { // list which accepts animals(animal must conform to identifiable)
            animal in Cell(animal: animal) // loopint through animals and passing each animal to cell
        }
    }
}

// now lets make changes in our content_previews Mytable_Previews

struct Mytable_Previews: PreviewProvider { // we have renamed Content_previews
    static var previews: some View {
        Mytable(animals: animalList) // showing MyTable and passing animalList to it.
    }
}

Done!!! now resume the preview you should see the list with cells!!! as given below

🙁

Only goats, that’s not what we want. Let’s take a look at our data source you will see that we have kept all the id:1 for all animals so only one type of data is being shown let’s update our data source as given below

let animalList = [
    Animal(id: 1, name: "goat", image: "goat"),
    Animal(id: 2, name: "dog", image: "dog"),
    Animal(id: 3, name: "deer", image: "deer"),
    Animal(id: 4, name: "cat", image: "cat"),
] // updated all ids they are all different now

//after this your file should like
import SwiftUI

struct Animal:Identifiable {
    var id: Int
    var name: String
    var image: String
}

let animalList = [
    Animal(id: 1, name: "goat", image: "goat"),
    Animal(id: 2, name: "dog", image: "dog"),
    Animal(id: 3, name: "deer", image: "deer"),
    Animal(id: 4, name: "cat", image: "cat"),
]

struct ContentView: View {
    var body: some View {
        Mytable(animals: animalList) // this will actually show on app run
    }
}

struct Mytable_Previews: PreviewProvider {
    static var previews: some View {
        Mytable(animals: animalList) // this is for preview only 
    }
}

struct Cell: View {
    var animal:Animal
    var body: some View {
        HStack {
            Text(animal.name)
        Spacer()
            Image(animal.image)
            .resizable()
            .aspectRatio(contentMode:.fit)
            .frame(maxWidth:40)
        }
    }
}

struct Mytable: View {
    var animals: [Animal]
    var body : some View {
        List(animals) {
            animal in Cell(animal: animal)
        }
    }
}

Now resume preview again or run your app you will have a list of animals

Hope you enjoyed it.

A pat on the back !!