Coding and Renaissance

These days we talk a lot about coding as the new critical thinking and as new literature. I want to go beyond, perhaps with the coding, you are back to the old science, that before the French Revolution (from That moment onwards Scientists have always Been More classified in sectoral almost confused with the “technical” disciplines).

Before this (the two World Conflicts completed this change) the Scientists were multidisciplinary, think of Galileo, Leonardo And Others; they were philosophers, inventors, hackers (curious).

Today with the coding maybe we again individually purchasing this multidisciplinarity, returning to take care of the diversity of Humanity aspects (the software must solve a problem) but must interface with Being Human (psychology visual, emotional, etc.), dropped in the context (sociology.) Are the machines push us to rediscover the humanity that we were losing?

The Software Craftsman

I’m very enthusiastic about the book “The Software Craftsman: Professionalism, Pragmatism, Pride” by Sandro Mancuso (https://amzn.to/34ksWKV). It’s in my top three for the IT book. I would like to suggest to every people that has some interest in software development, not only for the engineers. The book explains a mindset (using a hype word) and some good practices that the software developer should have in their work. These practice, habits or how you want to call them are necessary to create good software but in the process to create good products are involved also other professional figures (i.e. manager), so if they know what’s good for the developers, software architects and so on, it’s better for everyone, for the engineer, for the manager and the customers. So read it.

Contents

The book expands the concepts that you can find in the Manifesto (https://manifesto.softwarecraftsmanship.org/). The main things are:

  • Write good software (that it working is obvious)
  • Mentorship the younger developer
  • Use TDD and other Agile practices
  • Collaborate with everyone, also say “no” if it’s necessary to have good software.

About TDD and Agile practice they are not connected to the “Craftsman”, in this time it seems that better thing to do to have good software, if tomorrow we have other practices that permit us to make better software, the real Craftsman have to use the new things.

In the end, learn and share (forever).

Note: English is not my native language, so I’m sorry for some errors. I appreciate it if your correct me.

Toolbar and Customization

In the previous post (https://nicoladefilippo.com/navigation-in-swiftui/) we saw how to navigate between the views in the app. In this post, we see another element to implement the navigation, the toolbar and how to customize the navigation bar.

Toolbar

First, create an empty project:

struct ContentView: View {
    var body: some View {
            Text("Hello, world!")
                .padding()
    }
}

Add the NavigationView:

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello, world!")
                    .padding()
            }       
        }
    }
}

Now add the toolbar:

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello, world!")
                    .padding()
            }
            .navigationBarTitle("Title", displayMode: .inline)
            .toolbar(content: {
                NavigationLink(destination: EmptyView()) {
                    Image(systemName: "paperplane")
                    .font(.title)
                    .foregroundColor(.primary)
                }
            })
        }
    }
}

First, add a navigationTitle or a navigationBarTitle then add the toolbar. In the content you can write any object with user interaction (i.e. Button); in this example, we use a NavigationLink showing an image, paperplane, and how destination an EmptyView, for real app replace it with your view.

Customize

Start to the end:

We want to have a purple navigationBar, with a custom font, and a different arrow to come back. How to do it?

 init() {
        let navBarAppearance = UINavigationBarAppearance()
            
        navBarAppearance.backgroundColor = UIColor.purple
        
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.systemRed,  .font: UIFont(name: "ArialRoundedMTBold", size:35)!]
    
        navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.systemRed, .font: UIFont(name: "ArialRoundedMTBold", size: 20)!]
               
        
        
        UINavigationBar.appearance().standardAppearance = navBarAppearance
        UINavigationBar.appearance().scrollEdgeAppearance = navBarAppearance
        UINavigationBar.appearance().compactAppearance = navBarAppearance
        
        navBarAppearance.setBackIndicatorImage(UIImage(systemName: "arrow.turn.up.left"), transitionMaskImage: UIImage(systemName: "arrow.turn.up.left"))
                
        UINavigationBar.appearance().tintColor = UIColor.white
    }

We need to write an init function in the ContentView. In this function, we declare a navBarAppearance of UINavigationBarAppearance type.

For this, we define the property backgroundColor, largeTitleTextAttributes and titleTextAttributes (you can try to use different value and see the different effect).

Then we use the navBarAppearance for the standardAppearance, scrollEdgeAppearance and compactAppearance. Where:

  • standardAppearance is the appearance settings for a standard-height navigation bar
  • scrollEdgeAppearance is the appearance settings to use when the edge of any scrollable content reaches the matching edge of the navigation bar.
  • compactAppearance is the appearance settings for a compact-height navigation bar.

(See https://developer.apple.com/documentation/uikit/uinavigationbar/3198028-standardappearance )

To change the image for the backIndicator use the setBackIndicatorImage, instead to change the colour of the image in the toolbar, set a value to UINavigationBar.appearance().tintColor.

To change the colour to a tabbar:

UITabBar.appearance().barTintColor = .purple

You can use the tabbar example from the previous post and work on it.

If you want, you can ask me for some arguments and I will try to satisfy you.

Note: English is not my native language, so I’m sorry for some errors. I appreciate it if your correct me.

List in SwiftUI

In this post, I explain how to use the list to show a list of elements.

The first simple example:

struct ContentView: View {
    var body: some View {
        List  {
            Text("Element One")
            Text("Element Two")            
        }
    }
}

The magic word is List, which has two text elements:

The better way to iterate a list is to use a ForEach:

struct ContentView: View {
    var body: some View {
        List  {
            ForEach(1...10, id: \.self) { index in
                Text("Element \(index)")
            }
        }
    }
}

To have:

What’s is the id? What’s its purpose? The id identifies uniquely every element of the list, in this case with \.self the id is the value of the element. In the index is stored the current value of the element.

The id is very important, so we can define it for our structure using the Identifiable protocol:

struct Vehicle: Identifiable {
    var id = UUID()
    var name: String
    var image: String
}

Change the code in the example in this way:

struct ContentView: View {
    var vehicles = [Vehicle(name: "car", image: "car"),
                    Vehicle(name: "bus", image: "bus"),
                    Vehicle(name: "tram", image: "tram"),
                    Vehicle(name: "bicycle", image: "bicycle")]
    
    var body: some View {
        List(vehicles) { vehicle in
            Text(vehicle.name)
        }
    }
}

In the previous code is declared and initialized an array of Vehicle and the list iterates on that array, to have:

Custom Row

In the image field, I used the name from https://developer.apple.com/sf-symbols/ SanFrancisco symbols, you can use also your images to load them in the assets.

var body: some View {
        List(vehicles) { vehicle in
            HStack {
                Image(systemName: vehicle.image)
                Text(vehicle.name)
            }            
        }
    }

The text is not aligned, to fix it we have to do some change, set the resizable property at the image and set a fixed size for the image. Before doing that is better to extract the code that shows the row to have clean code. From the contextual menu, select show code action and then extract subview. Rename the ExtractSubview in RowView.

struct RowView: View {
    var body: some View {
        HStack {
            Image(systemName: vehicle.image)
            Text(vehicle.name)
        }
    }
}

There are some errors because the vehicle is not found, so fix it:

struct RowView: View {
    var vehicle: Vehicle
    var body: some View {
        HStack {
            Image(systemName: vehicle.image)
            Text(vehicle.name)
        }
    }
}

Now change the image properties:

struct RowView: View {
    var vehicle: Vehicle
    var body: some View {
        HStack {
            Image(systemName: vehicle.image)
                .resizable()
                .frame(width: 60, height: 60)
            Text(vehicle.name)
        }
    }
}

At the end change the code in the List:

var body: some View {
        List(vehicles) { vehicle in
            RowView(vehicle: vehicle)
        }
    }

To have:

Swipe action

With SwiftUI is simple to implement the swipe action to delete an element:

var body: some View {
        List {
            ForEach(vehicles) { vehicle in
                RowView(vehicle: vehicle)
            }
            .onDelete { (indexSet) in
                self.vehicles.remove(atOffsets: indexSet)
            }
        }
    }

Note that we have to use the ForEach because the onDelete is defined for the ForEach and not for the List.

We have also to change the declaration of the array in:

@State var vehicles = [Vehicle(name: "car", image: "car"),
                    Vehicle(name: "bus", image: "bus"),
                    Vehicle(name: "tram", image: "tram"),
                    Vehicle(name: "bicycle", image: "bicycle")]
    

We have to add @State because we want to propagate the change of the vehicles in the view.

The complete code is:

struct Vehicle: Identifiable {
    var id = UUID()
    var name: String
    var image: String
}

struct ContentView: View {
    @State var vehicles = [Vehicle(name: "car", image: "car"),
                    Vehicle(name: "bus", image: "bus"),
                    Vehicle(name: "tram", image: "tram"),
                    Vehicle(name: "bicycle", image: "bicycle")]
    
    var body: some View {
        List {
            ForEach(vehicles) { vehicle in
                RowView(vehicle: vehicle)
            }
            .onDelete { (indexSet) in
                self.vehicles.remove(atOffsets: indexSet)
            }
        }
    }
}

struct RowView: View {
    var vehicle: Vehicle
    var body: some View {
        HStack {
            Image(systemName: vehicle.image)
                .resizable()
                .frame(width: 60, height: 60)
            Text(vehicle.name)
        }
    }
}

To have:

Note: English is not my native language, so I’m sorry for some errors. I appreciate it if your correct me.

State, Binding and Refactoring

State

In every software or application we need to share information from the different components, in this post we’ll see how to do it in SwiftUI.

In the first example, we want to make a simple application that tapping on a button, the app shows the number of times that the button is tapped, more simple to show that to explain:

Let’s see the code:

struct ContentView: View {
    @State var counter: Int = 0
    
    var body: some View {
        VStack {
            Text(("Tapped \(counter) times"))
                .padding()
            Button(action: {counter = counter + 1}, label: {
                Text("Tap")
            })
        }
    }
}

The counter variable is defined as @State, this means that every change to the counter is propagated in the application.

Thus, every time that we tap the button, the counter is increased by one.

Note: the code counter is initialized to 0, if you remove this, to change in

@State var counter: Int

You’ll have an error in the ContentView_Previews, to fix it, change the code in this way:

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(counter: 0)
    }
}

In this way, the counter is initialized in the preview. We have to initialize the counter in every place where the ContentView is called.

To see as refactoring the code adding some code:

struct ContentView: View {
    @State var counter: Int = 0
    
    var body: some View {
        VStack() {
            Text(("Tapped \(counter) times"))
                .padding()
            HStack {
                Image(systemName: "plus.message")
                Button(action: {counter = counter + 1}, label: {
                    Text("Tap")
                })
            }
        }
    }
}

We have a HStack with an Image and the Button:

Now, go on the code, press control and click on the HStack, will appear a menu:

Select “Show Code Action”, will appear:

Now rename the ExtractView (default name for the extracted view) to PlusButton:

struct PlusButton: View {
    var body: some View {
        HStack {
            Image(systemName: "plus.message")
            Button(action: {counter = counter + 1}, label: {
                Text("Tap")
            })
        }
    }
}

Binding

We have an error: cannot find counter in the scope. It’s correct, we don’t have the definition of the counter in the PlusButtonView. We have to do a special declaration, using the keyword @Binding.

struct ContentView: View {
    @State var counter: Int = 0
    
    var body: some View {
        VStack() {
            Text(("Tapped \(counter) times"))
                .padding()
            PlusButton(counter: $counter)
        }
    }
}

struct PlusButton: View {
    @Binding var counter: Int
    var body: some View {
        HStack {
            Image(systemName: "plus.message")
            Button(action: {counter = counter + 1}, label: {
                Text("Tap")
            })
        }
    }
}

With the @Binding we can share and propagate the counter access in a different view. Simplify, we can say that with State, we say to monitor the change, with Binding get the change.

Note as is changed the way to pass counter in:

PlusButton(counter: $counter)

It’s necessary to use the $ near the counter variable, with the dollar symbol we specify the binding.

We can also use more PlusButton:

struct ContentView: View {
    @State var counter: Int = 0
    
    var body: some View {
        VStack() {
            Text(("Tapped \(counter) times"))
                .padding()
            PlusButton(counter: $counter)
            PlusButton(counter: $counter)
            PlusButton(counter: $counter)
        }
    }
}

Running the code you can verify that tapping every single button change the single common value (counter).

Note: English is not my native language, so I’m sorry for some errors. I appreciate it if your correct me.