Home SwiftUI - Create Expandable List (Section Approach)
Post
Cancel

SwiftUI - Create Expandable List (Section Approach)

🌑 Outline

List View in Swift UI has the capability to support expandable lists without writing any extra logic for expansion or collapse. The section in a list can serve as the main cell and the cell can serve as the expended cell.

Unlike UIKit, SwiftUI List View adjusts automatically based on the data source. No need to reload or delete cells just provide the expected format data and it will create the UI for you. List View has an initializer with a section which can be used here to set up an expandable list.

🌓 Talk is cheap. Show me the code

⚡ Create a protocol to represent a cell Item.
⚡ Create a model class for the main category implementing cell item.
⚡ Create a model class for the child category implementing cell item.
⚡ Main category model should contain child categories as an array of objects

1
2
3
4
5
6
7
 //Cell Item
public protocol MenuItem: Identifiable {
    var id: UUID  { get }
    var title: String { get }
    var image: String? { get }
    var childs: [any MenuItem]? { get }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 //Main Category
public struct Organization: MenuItem {
    public var id = UUID()
    var name: String
    public var image: String?
    var products: [Product]?

    public var title: String {
        return name
    }
    
    public var childs: [any MenuItem]? {
        return self.products
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Child Category
public struct Product: MenuItem {
    public var id = UUID()
    var name: String
    public var image: String?
    
    public var title: String {
        return name
    }
    
    public var childs: [any MenuItem]? {
        return nil
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//Create List View
public struct ExpandableList: View {
    public var listItems: [any MenuItem] = []
    
    public init() {
        setupListItems()
    }

    fileprivate mutating func setupListItems() {
        // setup Employee List
        let product1 = Product(name: "iPhone", image: "iphone.gen1.circle")
        let product2 = Product(name: "Apple Watch", image: "watchface.applewatch.case")
        let product3 = Product(name: "iPad", image:"ipad.gen2")
        let product4 = Product(name: "Pixel Phone", image: "candybarphone")
        let product5 = Product(name: "Galaxy Phone", image: "flipphone")
        let product6 = Product(name: "Galaxy Watch", image: "stopwatch")
        let product7 = Product(name: "Smart Ring", image: "ring.circle")
        let product8 = Product(name: "Airdopes 131", image: "airpods")
        // setup Department
        let AppleOrg = Organization(name: "Apple", products: [product1, product2, product3])
        let googleOrg = Organization(name: "Google", products: [product4])
        let samsungOrg = Organization(name: "Samsung", products: [product5, product6])
        let boatOrg = Organization(name: "Boat", products: [product7, product8])
        self.listItems = [AppleOrg, googleOrg, samsungOrg, boatOrg]
    }
    
    public var body: some View {
        List(self.listItems, id: \.id, children: \.childs) { item in
            HStack {
                if let image = item.image {
                    Image(systemName: image)
                        .frame(width: 35, height: 35)
                }
                Text(item.title)
                    .font(.system(.title3, design: .rounded))
                    .bold()
            }
        }
    }
}

Download Complete Source Code: Expandable List

🌕 How it Looks

Note: A jerk is observed with iOS 16.4 SDK in the list.

This post is licensed under CC BY 4.0 by the author.

Simplify Template Pattern (Behaviour Pattern)

What's System Design

Comments powered by Disqus.