This article is related notes for the 1st episode of Stanford University's CS193p course.

cs193p Class Intro:

The lectures for the Spring 2023 version of Stanford University's course CS193p (Developing Applications for iOS using SwiftUI) were given in person but, unfortunately, were not video recorded. However, we did capture the laptop screen of the presentations and demos as well as the associated audio. You can watch these screen captures using the links below. You'll also find links to supporting material that was distributed to students during the quarter (homework, demo code, etc.).

cs193p class website: https://cs193p.sites.stanford.edu/2023


Create a new iOS Project

Go File -> New -> Project

Get Understand "Hello World" Code

Full "Hello World" Code

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

struct and View

struct ContentView: View {
      ...
      ...
}
  • struct states for structure and it is the heart of SwiftUI. It can have variables and functions in it. Swift is not an object oriented programing language, so struct is NOT a class. It is a funtional programming language.
  • ContentView is the name of the struct.
  • View means ContentView struct behaves like a View.

var

struct ContentView: View {
    var body: some View {
            ...
            ...
    }
}
  • var is a keyword for variable, and body is the variable name. Other variable may looks like:
var i: Int
var s: String

Computed Property

Let's take a look at what in the body:

    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
  • var body is a property, and the value of body variabe is NOT stored somewhere. It is computed, every time when the program runs. It will compute the code inside. In this case, it is the part below:
                                                {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }

some View is unlike String or Int. It is some kinds of View, any different types of View. As long as it is a View.

VStack (Vertical Stack)

        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
  • creating instance of structs: like image struct, Image(systemName: "globe"); or text struct, Text("Hello, world!").
  • named parameters: systemName is a named parameter.
  • Parameter defaults: There are other arguments could be specified, but we take the default value.
  • This VStack has 2 struct behaves like a View. It has Image and Text struct. However, VStack itself is also a struct behaves like a View. We can have argumant for VStack, For example:
        VStack(alignment: .leading, spacing: 20) {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
  • What about the whole thing inside the VStack?

    • It is a parameter of VStack, the whole thing should looks like this:
        VStack(content: {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        })
  • The VStack is also called @ViewBuilder. @ViewBuilder can trun list of views (Image, Text) to TupleView.

View modifier

            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
  • The .imageScale and .foregroundStyle is called view modifier. The Image view will return value to .imageScale and then .imageScale will also return to .foregroundStyle. So they can chain together.

Scope of a view modifier

The scope of a view modifier is important. If the scope is different, it will show differently.

view-modifier-scope-1

▲ Scope 1

view-modifier-scope-2

▲ Scope 2

Let's Start Creating Card

a-single-card

▲ Created a Single Card with white background

four-cards

▲ Created 4 cards

import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack {
            CardView(isFaceUp: true)
            CardView()
            CardView()
            CardView()
        }
        .foregroundColor(.orange)
        .padding()
    }
}

struct CardView: View {
    var isFaceUp: Bool = false
    var body: some View {
        ZStack(content: {
            if isFaceUp {
                RoundedRectangle(cornerRadius: 12)
                    .foregroundColor(.white)
                RoundedRectangle(cornerRadius: 12)
                    .strokeBorder(lineWidth: 2)
                Text("👻").font(.largeTitle)
            } else {
                RoundedRectangle(cornerRadius: 12)
            }
        })
    }
}

#Preview {
    ContentView()
}

four-cards-can-control-face-up-and-down

▲ Created 4 cards with a parameter to control it's face up and down

Note: Every var has to have a value, but we can give a defalut value.