Week 4 of Learning SwiftUI

Animations, Data Persistence, and Multiple Views. Oh my!

Posted by Joe Speakman on February 10, 2021 · 9 min read



Day 17 (Day 32)

Animations! So today, we start learning how animations work. However, we aren’t creating a new app. Project 7 will be the next app. Instead, on day three, we will be adding animation to a previous project. Today we cover implicit and explicit animations, as well as animation bindings.

Animations in SwiftUI are incredibly simple and are built into SwiftUI by using .animation(). There are 5 types of implicit animations: .default, .easeIn, .easeOut, .easeInOut, and .linear. Additionally, you can customize these animations to any style desired with various parameters show in this code:

.animation(
    Animation.easeInOut(duration: 1)
        .repeatForever(autoreverses: true)
)

To continually animate the object, .repeateForever is used.

Explicit animations are more complex and require a bit more setup however give you greater control over the animation. SwiftUI is still going to figure out the animation; nevertheless, we can control items such as the state of animation and the degrees of the animation, such as .rotation3DEffect allows you to rotate the 2-dimensional item displayed in 3-dimensional space.

.rotation3DEffect(.degrees(animationAmount), axis: (x: 1, y: 0, z: 0))
Day 18 (Day 33)

Today we are embarking on continuing learning animations, and we cover multiple ways of using animations like animating gestures and controlling the animation stack.

Having control over the animation stack allows you to customize multiple aspects of the animation, just like adding modifiers to your view. Paul does a great job of explaining it in today’s lesson.

Gestures are a great way to give users more ways to interact with your app. A common one is a swipe to refresh. Whoever invented that idea is a genius. In SwiftUI a gesture can be done with one @State object and adding the .gesture() modifier to the object. To add animation to it, you would add the .animation modifier to the block.

Day 19 (Day 34)

With the work done over the past few days, we are now at the end of this section and offered to challenge our learning further by these challenges:

  • When you tap the correct flag, make it spin around 360 degrees on the Y axis.
  • Make the other two buttons fade out to 25% opacity.
  • And if you tap on the wrong flag? Well, that’s down to you – get creative!

Taking the exam for this project, I scored a thrilling 92%, My highest yet! I am thrilled to use animations in other projects!

Day 20 (Day 35)

Today is a consolidation day, just recapping and reviewing what learning has happened with the last three projects, from strings to understanding app bundles. I feel confident in the topics touch on in the past three projects. have all provided some strong learning in key topics such as App Bundles, DatePicker, CoreML, UITextChecker, and more! UITextChecker has to be the most interesting for me so far, as I have never worked with it before.

Day 21 (Day 36)

Today we are starting a new project called iExpense, a local expense tracker that allows the user to save items to two categories: personal and business. Additionally, we are integrating Data persistence into the project for a better user experience. Start of a new project. Today we started learning about the limitations that an @State has, as they don’t share data to other views; SwiftUI has @ObservedObject to help with that.

There are many ways of adding multiple views to a SwiftUI, One way is using a .sheet(), same with an alert you would start with adding a @State object:

@State private var showingAddExpense = false

To toggle the view showing you would use code like this to show the second view as a pop up sheet:

        .sheet(isPresented: $showingAddExpense) {
            AddView(expenses: self.expenses)
        }

The vision behind the app is to have data be persistent through the various launches. There are multiple ways of handling this task. With the tiny amount of data that we need to do this with, UserDefaults is an excellent way of achieving that goal. Later in this project, we put together the code to give the retrieved data from UserDefaults to the List so that it can create the cells, based on that data. Before we handle that we must implement a way for the user to delete data from the List. the great news is List has a built-in method called .onDelete(). Additionally we will need to add a function to handle the deletion:

    func removeItems(at offsets: IndexSet) {
        expenses.items.remove(atOffsets: offsets)
    }

This code block takes the array of items and deletes the item matching the UUID provided by .onDelete(), Next to store the user input data.

UserDefauts

Is a data persistence model that loads every time you open the app, so it is ideal to use User Defaults sparingly. User defaults allow you to store data with data for a key system where the key is a string that you would call to save and retrieve data:

 if let encoded = try?
                encoder.encode(items) {
                UserDefaults.standard.set(encoded, forKey: "Items")
            }
Day 22 (Day 37)

Today we start to put together the project from what we learned from the previous day. Starting with adding the list to the app and creating data that can be deleted and identified. By adding the Identifiable tag to the ExpenseItem struct

struct ExpenseItem: Identifiable, Codable {
    var id = UUID()
    let name: String
    let type: String
    let amount: Int
}

When making something identifiable, there must be an id variable; this will generate a UUID for the item. UUIDs are a string with a randomly generated number.

Day 23 (Day 38)

Today is the final day of iExpense, and all of the “polish” was added at the end off yesterday, all that is left now are the recommended challenges:

  • Add an Edit/Done button to ContentView so users can delete rows more easily.
  • Modify the expense amounts in ContentView to contain some styling depending on their value – expenses under $10 should have one style, expenses under $100 another, and expenses over $100 a third style. What those styles are depend on you.
  • Add some validation to the Save button in AddView. If you enter “fish” or another thing that can’t be converted to an integer, show an alert telling users what the problem is.

Additionally, to do the end of project quiz, scoring a 91% with only one out of twelve questions wrong. Despite the challenges this week has brought, I am glad I learned some new skills that I can build upon.

Week four.

I learned a lot of new content, however I found a significant struggle with articulating these topics as written content. As well as a lack of motivation Next week I hope to have more success and motivation. 😅