---
title: 'SwiftUI Prototype Tutorial 5 of 5: Profile View'
teaser: 'In the final installment of our SwiftUI tutorial series, we''ll create our
  Profile view.

  '
tags: swiftui,swift,design,ios
author: Devin Jameson
published_on: 2020-07-09
---

In the final installment of our SwiftUI tutorial series, we'll create
our Profile view.

**Posts in this series:**

- [Part 1: Project Setup](https://thoughtbot.com/blog/swiftui-prototype-tutorial-1-of-5-project-setup)
- [Part 2: Category Card View](https://thoughtbot.com/blog/swiftui-prototype-tutorial-2-of-5-category-card-view)
- [Part 3: Categories List](https://thoughtbot.com/blog/swiftui-prototype-tutorial-3-of-5-categories-list)
- [Part 4: Dynamic Categories & Navigation](https://thoughtbot.com/blog/swiftui-prototype-tutorial-4-of-5-dynamic-categories-and-navigation)
- [Part 5: Profile View](https://thoughtbot.com/blog/swiftui-prototype-tutorial-5-of-5-profile-view)

Here's how our prototype will look at the end of this section.

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The profile tab is blue and the categories tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Above this headline on the left is the text "Premium Member" in gray. Above the headline on the right is a circular image of Devin Jameson. Below the headline are three selectable rows stacked on top of one another. Each row has text on the left and a gray, right-facing arrow on the right. Between each row of text is a grey dividing line. From top to bottom, the text for each row reads "Saved Articles", "Followers", and "Following".](https://images.thoughtbot.com/blog-vellum-image-uploads/4CGsYLGnQDafQJ2tGKfh_12.jpg)

First, let's make a new file for our Profile code following the same process we
used to create our Categories file in [Part Two](https://thoughtbot.com/blog/swiftui-prototype-tutorial-2-of-5-category-card-view).

To get our Live Preview working, we'll replace `Profile()` on line 19 with
`ContentView()`.

```swift
struct Profile_Previews: PreviewProvider {
    static var previews: some View {
        ContentView() // Replace Profile() with ContentView()
    }
}
```

Back in ContentView.swift, we'll wire up our Profile tab item to our Profile
view by replacing `Text("Second View")` with `Profile()`.

```swift
Categories()
    .font(.title)
    .tabItem {
        VStack {
            Image(systemName: "globe")
            Text("Categories")
        }
}
.tag(0)
Profile() // Change Text("Second View") to Profile()
    .font(.title)
    .tabItem {
```

We'll also change the default tab of our TabView to show the Profile view by
providing `1` to our selection parameter instead of `0`.

```swift
struct ContentView: View {
    @State private var selection = 1

    var body: some View {
```

Now let's add a NavigationView to our Profile view with our name as the title.

```swift
struct Profile: View {
    var body: some View {
        NavigationView {
            Text("Hello, World!")
                .navigationBarTitle("Devin Jameson")
        }
    }
}
```

Notice that we use `.navigationBarTitle()` *within* `NavigationView`.

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The profile tab is blue and the categories tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Below this headline, in the middle of the screen, is the text "Hello, World!"](https://images.thoughtbot.com/blog-vellum-image-uploads/qpd7fhPS2aL18UzK1rvk_2.jpg)

Next, we'll add some content to our Profile view. Since we want to display three
navigation links here, we can start by creating an array that stores the names
of our links. We'll call this variable `profileLinkNames.`

```swift
struct Profile: View {
    let profileLinkNames: [String] = ["Saved Articles", "Folowers", "Following"]
```

Now we can list these strings using something Swift provides called `ForEach`,
which enables us to provide dynamic content to views. We'll put the `ForEach` in
a `VStack` and remove `Text("Hello, World!")`.

```swift
let profileLinkNames: [String] = ["Saved Articles", "Followers", "Following"]

var body: some View {
    NavigationView {
        VStack {
            ForEach(profileLinkNames, id: \.self) { profileLinkName in
                Text(profileLinkName)
                    .font(.body)
            }
        }
        .navigationBarTitle("Devin Jameson")
    }
}
```

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The profile tab is blue and the categories tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Below this headline, in the middle of the screen, are three lines of text stacked on top of one another. From top to bottom, they read "Saved Articles", "Followers", and "Following".](https://images.thoughtbot.com/blog-vellum-image-uploads/YxZc6GQ7StKyX60D58wo_3.jpg)

You'll notice we include the  `id` parameter in `ForEach`.  Swift requires this
`id` so it can differentiate between elements in our array when making updates
to the UI. Providing the argument `\.self` gives each element an id equal to its
own value, which is fine in this case.

Now that we're displaying some items in our Profile view, we can move on to
styling them. Let's begin by adding a chevron right symbol next to each item.
We'll embed the Text and Image views in an `HStack` add a `Spacer()` view in
between them to spread them apart.

```swift
VStack {
    ForEach(profileLinkNames, id: \.self) { profileLinkName in
        HStack { // Embed it all in an HStack
            Text(profileLinkName)
                .font(.body)
            Spacer() // Spread the Text and Image views apart
            Image(systemName: "chevron.right") // Add symbol
                .foregroundColor(Color(.systemGray3))
        }
    }
}
```

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The profile tab is blue and the categories tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Below this headline, in the middle of the screen, are three lines of text stacked on top of one another. From top to bottom, they read "Saved Articles", "Followers", and "Following". These lines of text are positioned on the far left of the screen. On the right side of the screen, parallel to each line of text, is a gray arrow pointing right.](https://images.thoughtbot.com/blog-vellum-image-uploads/lQNY6JNQSvaaUYQ8AK75_4.jpg)

Now let's add a `Divider()` view after our `HStack` and embed the `HStack` in a
`VStack`. This will give us a divider underneath each profile link.

```swift
VStack {
    ForEach(profileLinkNames, id: \.self) { profileLinkName in
        VStack { // Embed both the HStack and Divider in a VStack
            HStack {
                Text(profileLinkName)
                    .font(.body)
                Spacer()
                Image(systemName: "chevron.right")
                    .foregroundColor(Color(.systemGray3))
            }
            Divider() // Add a divider
        }
    }
}
```

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The profile tab is blue and the categories tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Below this headline, in the middle of the screen, are three lines of text stacked on top of one another. From top to bottom, they read "Saved Articles", "Followers", and "Following". These lines of text are positioned on the far left of the screen. On the right side of the screen, parallel to each line of text, is a gray arrow pointing right. Below each line of text is a thin grey dividing line.](https://images.thoughtbot.com/blog-vellum-image-uploads/rGKwYNvgQsWUC1voU8Z1_5.jpg)

Now for some padding around each `HStack`.

```swift
HStack {
    Text(profileLinkName)
    Spacer()
    Image(systemName: "chevron.right")
        .foregroundColor(Color(.systemGray3))
}
.padding(EdgeInsets(top: 17, leading: 21, bottom: 17, trailing: 21))
Divider()
```

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The profile tab is blue and the categories tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Below this headline, in the middle of the screen, are three lines of text stacked on top of one another. From top to bottom, they read "Saved Articles", "Followers", and "Following". These lines of text are positioned on the far left of the screen. On the right side of the screen, parallel to each line of text, is a gray arrow pointing right. Below each line of text is a thin grey dividing line. Comapred to the previous image, there is more space between each line of text.](https://images.thoughtbot.com/blog-vellum-image-uploads/0VVnOIUdTfuLR2ia8URc_6.jpg)

It's not obvious, but behind the scenes, each `VStack` in our view is adding
some extra spacing between our profile links. Let's tell each `VStack` not to do
that.

```swift
NavigationView {
 VStack(spacing: 0) {
     ForEach(profileLinkNames, id: \.self) { profileLinkName in
         VStack(spacing: 0) {
             HStack {
```

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The categories tab is blue and the profile tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Above this headline in the middle of the screen are three lines of text stacked on top of one another. From top to bottom, they read "Saved Articles", "Followers", and "Following". These lines of text are positioned on the far left of the screen. On the right side of the screen, parallel to each line of text, is a gray arrow pointing right. Below each line of text is a thin grey dividing line. Comapred to the previous image, there is less space between each line of text.](https://images.thoughtbot.com/blog-vellum-image-uploads/ndCxu8HT2ewrX9W4SRy3_7.jpg)

Our chevron right symbol also looks a little big , so we'll make that smaller.

```swift
Image(systemName: "chevron.right")
    .foregroundColor(Color(.systemGray3))
    .font(.system(size: 20))
```

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The categories tab is blue and the profile tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Below this headline, in the middle of the screen, are three lines of text stacked on top of one another. From top to bottom, they read "Saved Articles", "Followers", and "Following". These lines of text are positioned on the far left of the screen. On the right side of the screen, parallel to each line of text, is a gray arrow pointing right. Compared to the previous image, these gray arrows are smaller. Below each line of text is a thin grey dividing line.](https://images.thoughtbot.com/blog-vellum-image-uploads/g4DlimXYQyuJR0X66zxR_8.jpg)

You might notice that our Profile view code is becoming hard to read. Let's
clean it up.

Command + click on the `VStack` just beneath `ForEach` and select `Extract
Subview`. Boom! We now have a separate subview for each profile link. Let's
rename this subview from `ExtractedView` to `ProfileLink`. Right click on
`ExtractedView` and select Refactor > Rename. Type `ProfileLink` and hit enter.

Your ProfileLink view code should now look like this.

```swift
struct ProfileLink: View {
    var body: some View {
        VStack(spacing: 0) {
            HStack {
                Text(profileLinkName)
                    .font(.body)
                Spacer()
                Image(systemName: "chevron.right")
                    .foregroundColor(Color(.systemGray3))
                    .font(.system(size: 20))
            }
            .padding(EdgeInsets(top: 17, leading: 21, bottom: 17, trailing: 21))
            Divider()
        }
    }
}
```

Now we just have to pass our `profileLinkName` to the ProfileLink view.

```swift
ForEach(profileLinkNames, id: \.self) { profileLinkName in
    ProfileLink(profileLinkName: profileLinkName) // Pass profileLinkName to ProfileLink
}
```

```swift
struct ProfileLink: View {
    let profileLinkName: String // Add parameter for profileLinkName

    var body: some View {
        VStack(spacing: 0) {
            HStack {
                Text(profileLinkName)
                    .font(.body)
```

To finish up our link styling, we'll add another `Spacer()` below our `ForEach`
to push our links to the top of our `VStack`.

```swift
VStack(spacing: 0) {
    ForEach(profileLinkNames, id: \.self) { profileLinkName in
        ProfileLink(profileLinkName: profileLinkName)
    }
    Spacer()
}
```

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The categories tab is blue and the profile tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Below this headline are three lines of text stacked on top of one another. From top to bottom, they read "Saved Articles", "Followers", and "Following". These lines of text are positioned on the far left of the screen. On the right side of the screen, parallel to each line of text, is a gray arrow pointing right. Below each line of text is a thin grey dividing line.](https://images.thoughtbot.com/blog-vellum-image-uploads/iNlwsPI5SVmlLn3vYWPN_9.jpg)

Looking good!

Now we can wire up our navigation. Let's wrap our ProfileLink view in a
`NavigationLink` and set the destination to an empty Text view. To prevent our
profile links from turning blue, we'll use the `buttonStyle()` method on our
`NavigationLink`.

```swift
NavigationLink(destination: Text("")) {
    VStack(spacing: 0) {
        HStack {
            Text(profileLinkName)
                .font(.body)
            Spacer()
            Image(systemName: "chevron.right")
                .foregroundColor(Color(.systemGray3))
                .font(.system(size: 20))
        }
        .padding(EdgeInsets(top: 17, leading: 21, bottom: 17, trailing: 21))
        Divider()
    }
}
.buttonStyle(PlainButtonStyle())
```

To keep things simple, we'll leave the navigation link destination as an empty Text view.

We have a small issue now. If we try to navigate to one of the profile links, we
can only do so by clicking directly on the text or symbol. Clicking in the white
space in between them does nothing. To fix this, we can use the `contentShape()`
method on our `HStack`.

```swift
HStack {
    Text(profileLinkName)
        .font(.body)
    Spacer()
    Image(systemName: "chevron.right")
        .foregroundColor(Color(.systemGray3))
        .font(.system(size: 20))
}
.contentShape(Rectangle()) // Defining the shape of the HStack
.padding(EdgeInsets(top: 17, leading: 21, bottom: 17, trailing: 21))
```

![The prototype we'll be creating, previewed on an iPhone 11 Pro Max. A cursor is clicking on the screen to navigate to different views. The prototype has two tabs shown at the bottom of the screen: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The profile tab is blue and the categories tab is black. The Profile view contains a headline with the name "Devin Jameson". Above the bottom tab bar are three selectable rows stacked on top of one another. Each row has text on the left and a gray, right-facing arrow on the right. Between each row of text is a grey dividing line. From top to bottom, the text for each row reads "Saved Articles", "Followers", and "Following". The cursor is clicking on each of these rows, which brings us to a new screen. On the top left of this screen is a blue back button with the text "Categories". The bottom tab bar is still on this screen. The cursor then clicks on this back button to navigate to the prior screen.](https://images.thoughtbot.com/blog-vellum-image-uploads/Z5PcbG2nSqmzf7cOrxVo_10.gif)

Now let's handle the rest of the navigation bar elements.

To add content to the navigation bar area, we can use the `navigationBarItems`
method in our `NavigationView`. This method takes arguments for `leading` and
`trailing` parameters, to which we can provide Views.

Let's add the text `Premium Member` within the leading view and leave the
trailing view out for now.

```swift
.navigationBarTitle("Devin Jameson")
.navigationBarItems(
    leading: // Add our leading view
    Text("Premium Member")
        .font(.body)
        .foregroundColor(Color(.systemGray)),
)
```

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The profile tab is blue and the categories tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Above this headline on the left is the text "Premium Member" in gray. Below the headline are three selectable rows stacked on top of one another. Each row has text on the left and a gray, right-facing arrow on the right. Between each row of text is a grey dividing line. From top to bottom, the text for each row reads "Saved Articles", "Followers", and "Following".](https://images.thoughtbot.com/blog-vellum-image-uploads/aZdkU4UvRjejYRSUAToq_11.jpg)

Getting close! Now we can add our avatar image to our trailing view. First, add
your personal avatar image to your Assets in Xcode and name it whatever you
want.

Now let's add this avatar to our trailing view. We'll also make it resizable,
provide a size, and put it inside a circular clip shape.

```swift
.navigationBarItems(
    leading:
    Text("Premium Member")
        .font(.body)
        .foregroundColor(Color(.systemGray)),
    trailing: // Add trailing view
    Image("avatar")
        .resizable()
        .frame(width: 40, height: 40)
        .clipShape(Circle())) // Clip the image to a circle
```

![Our prototype running on iPhone 11 Pro Max. On the prototype is a bottom tab bar with two options: Categories and Profile. Above the categories tab label is a globe icon, and above the profile tab label is a person icon. The profile tab is blue and the categories tab is black. Above the bottom tab bar is the Profile view. The Profile view contains a headline with the name "Devin Jameson". Above this headline on the left is the text "Premium Member" in gray. Above the headline on the right is a circular image of Devin Jameson. Below the headline are three selectable rows stacked on top of one another. Each row has text on the left and a gray, right-facing arrow on the right. Between each row of text is a grey dividing line. From top to bottom, the text for each row reads "Saved Articles", "Followers", and "Following".](https://images.thoughtbot.com/blog-vellum-image-uploads/4CGsYLGnQDafQJ2tGKfh_12.jpg)

This concludes our journey with SwiftUI! By leveraging Apple's native
tools and APIs, we were able to whip up an extremely high-resolution
prototype with only a small amount of code.

I hope you learned something useful in this series! Tweet me
[@devinjameson](https://twitter.com/devinjameson) if you have any questions or
comments.

**Bonus:** our prototype is fully Dark Mode compatible! To see it in action,
click the play button on the top left of the XCode window. When the app starts
in Simulator, navigate to Features > Toggle Appearance.
