# Enumerated Array in SwiftUI

# Enumerated Array in SwiftUI

As you can see from the cover, in today’s post, I’m going to demonstrate how to create a dynamic list of transactions in SwiftUI using an enumerated array to make background color alternating. A ForEach would do the trick for the list, however, to make the row background conditional, we need to have access to the index of each row inside ForEach. In short, we can use an array of enumerated array. Continue reading to learn how.

The code in this post is available [here](https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202305-May%202023/DemoEnumerated20230527.swift).

If you like my posts, 😚consider tipping me at [buymeacoffee.com/xavierios](http://buymeacoffee.com/xavierios)

# Transaction Model

First of all, let’s build a model for the transaction data.

This struct conforms to the Identifiable protocol, which means it has a unique identifier. The struct has three properties:

1. `id`: This property is of type UUID (Universally Unique Identifier) and is initialized with a randomly generated unique identifier using the UUID() initializer.
    
2. `date`: This property represents a date and is of type Date.
    
3. `amount`: This property represents a numeric amount and is of type Double.
    

```swift
struct Transaction: Identifiable {
        let id = UUID()
        let date: Date
        let amount: Double
    }
```

# Array of Transactions

The next step is to prepare an array of transactions to be displayed. Let’s use a private state property.

```swift
struct ContentView: View {
	@State private var transactions: [Transaction] = []
	var body: some View {
		VStack {}
	}
}
```

And then populate the array with random data when the view loads. We can do this inside an onAppear view modifier. Then we need to populate the array and we can do this by generating 50 random transactions with dates ranging from 2010 to 2022 and amounts between 10 and 200.

```swift
struct ContentView: View {
	@State private var transactions: [Transaction] = []
	var body: some View {
			VStack {}
				.onAppear {
						for _ in 0...49 {
                    transactions.append(.init(
                        date: Calendar.current.date(from: .init(year: Int.random(in: 2010...2022), month: Int.random(in: 2...10), day: Int.random(in: 1...20)))!,
                        amount: Double.random(in: 10...200))
                    )
                }
                transactions.sort { $0.date > $1.date }
				}
	}
}
```

* The `date` property is set to a randomly generated date between the years 2010 and 2022, with a random month between 2 and 10, and a random day between 1 and 20. The [`Calendar.current.date`](http://Calendar.current.date)`(from:)` method is used to create a `Date` object from the specified components.
    
* The `amount` property is set to a random double value between 10 and 200.
    

And last step of the data prep is to sort the transactions in descending order based on their dates.

```swift
struct ContentView: View {
	@State private var transactions: [Transaction] = []
	var body: some View {
			VStack {}
				.onAppear {
						for _ in 0...49 {
                    transactions.append(.init(
                        date: Calendar.current.date(from: .init(year: Int.random(in: 2010...2022), month: Int.random(in: 2...10), day: Int.random(in: 1...20)))!,
                        amount: Double.random(in: 10...200))
                    )
                }
								// ------ New Code Below -------
                transactions.sort { $0.date > $1.date }
				}
	}
}
```

After the loop, the `transactions` array is sorted in descending order based on the `date` property using the `sort` method and a closure. The `$0` and `$1` are shorthand arguments referring to two elements being compared, and the closure specifies the sorting criteria (`$`[`0.date`](http://0.date) `> $`[`1.date`](http://1.date)), meaning it sorts the transactions based on the date property in descending order.

# UI Setup

Now let’s set up the UI before moving forward:

Embed the `VStack` inside a `NavigationView` and change the `VStack` to a `ScrollView`. Then give it a navigation title of “**Transaction Records**”.

```swift
struct ContentView: View {
        @State private var transactions: [Transaction] = []
        var body: some View {
            NavigationView {
                ScrollView {

                }
                .navigationTitle("Transaction Records")
            }
            .onAppear {
								//... code from above
            }
        }
    }
```

# Build the list with ForEach

Now inside the `ScrollView`, we need a `ForEach` to iterate over the transactions.

```swift
ForEach(transactions) { transaction in
                        HStack {
                            Text(transaction.date.formatted(date: .abbreviated, time: .omitted))
                            Spacer()
                            Text("$" + transaction.amount.toString1(2))
                        }
                        .padding(.horizontal, 20)
                        .padding(.vertical, 5)
                    }
```

The code above is a `ForEach` loop that iterates over the `transactions` array and creates a view for each element in the array.

Inside the loop, a `HStack` view is created to display the transaction information. It consists of two `Text` views and a `Spacer`.

The first `Text` view displays the formatted date of the transaction using the `formatted` method. It specifies the date style as `.abbreviated`, which will display the date in an abbreviated format, and the time style as `.omitted`, which will exclude the time component.

The second `Text` view displays the amount of the transaction. The amount is converted to a string with two decimal places using the `String(format, value)` method, and then concatenated with the "$" symbol.

The `HStack` view is then modified with padding using the `.padding` modifier. It adds horizontal padding of 20 points and vertical padding of 5 points to the view.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685242832622/46617eb7-fc29-4bda-9f30-2d232703352a.png align="center")

# Background Color Time!

Now it’s time to work on the background color alternating between rows.

Since we need the index of each row, we can use `enumerated()` function to access the index. However, this method returns a type called `EnumeratedSequence` and we need an array for ForEach, hence we need an extra wrapper to convert it back to an array. The item inside the array will be a pair of index (offset) and the element (transaction).

```swift
ForEach(Array(transactions.enumerated()), id: \\.element.id) { offset, transaction in
                        HStack {
                            Text("\\(offset + 1)").frame(width: 40)
                            Text(transaction.date.formatted(date: .abbreviated, time: .omitted))
                            Spacer()
                            Text("$" + transaction.amount.toString1(2))
                        }
                        .padding(.horizontal, 10)
                        .padding(.vertical, 11)
                        .background(offset % 2 == 0 ? Color.secondary.opacity(0.5) : Color.clear)
                    }
```

This time we use `Array(transactions.enumerated())` to get pairs of index and transaction. And we need to specify the id with a keypath `\\.`[`element.id`](http://element.id). The ForEach closure signature also updates from `transaction` to `offset, transaction`.

Then inside the HStack we add an extra Text View to display the offset value added by one as the row number.

And finally, we use a `background` view modifier to make the conditional background color, whose value is set with a ternary operator, checking if the offset value is even. If yes, the background color will be secondary, otherwise, it’s set to clear. Et voilà!

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1685242814931/56574b78-3c51-4d9a-92a7-e80301c6e529.png align="center")

And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.

I’ll see you in the next post!
