Everything You Wanted to Know About  the First Steps in SwiftUI

SwiftUI — is a new method of User Interface creation with some really kewl features. It can be used for all Apple platforms and has all the delicacy and power of Swift language. In this article I am going to make an introduction to SwiftUI, I’ll tell you about its possibilities and we’ll make a small app with a posts list together.

Make yourself comfortable and wish you a pleasant reading of this kind of a SwiftUI tutorial!

SwiftUI Strengths:

Declarative syntax

SwiftUI uses declarative syntax, which allows you to save time, since it’s extremely simple in writing and understanding.

import SwiftUI
 
struct FeatureCard: View {
  var landmark: Landmark
 
  var body: some View {
     landmark.featureImage
        .resizable()
        .aspectRatio(3/2, contentMode: .fit)
        .overlay(TextOverlay(landmark))}}

Declarative style is also used in animation. Using it one can easily add animation to almost any object and choose it out of the collection of the ready-made animated effects.

With such an easy animation implementation you do not need to look for other ways to make app live.

Design tools

Xcode is supplied with intuitive design tools, that make interface design with SwiftUI extremely simple and pleasant.

  • Drag and drop. Just drag UI elements to the canvas or code and then change the font, colour and other properties right there.
  • Dynamic replacement. Now the application is created and launched with Xcode. The canvas on the right is your app in real time, when you edit the canvas, Xcode changes immediately the code in your app with the help of «dynamic replacement».
  • Previews. You can also create previews for SwiftUI, to see everything what the users see, whether it’s DarkMode or localizations. In the preview you can add displaying for any device and orientation.

Native for all Apple platforms

SwiftUI works natively for all Apple platforms, whether it’s a smartphone, a tablet, a laptop, TV or Smart-Watch. It allows to create a perfect user interface.

Creating A New Project

Open XCode,and either click «Create a new Xcode project» in the XCode startup dialog box or choose File > New > Project.

Choose iOS in the next window as a platform, choose the app template and click the button «Next».

Then enter the name of the project and set «SwiftUI» as a user interface and click «Next».

Choose the place where your project should be saved on your Mac.

After that you should see the project window with an open ContentView file, in case it is not shown, choose it manually. You will see 2 editors: one on the left with code and one on the right with canvas ( if you do not see the canvas — click «Resume»).

Now a template project «Hello world» is in front of you with a single text field. Let’s play a bit with the editor on the right, hold ⌘ for this and click on the text field. You’ll then see the menu, where you should click «Show SwiftUI Inspector».

After that you’ll see the window with the text properties:

Let’s change the text itself, the font, the width, the colour. You will immediately see the changes on the canvases, but, stop, if you look at the left editor, you’ll see the same changes! It’s cool!

Let’s try to make all the same in the left editor. Hold ⌘ and click on the «Text» a window, which looks like the one for the right editor will appear.

Do all the same and you will see all the might of the dynamic replacement, all the code alterations lead to the changes on the canvas and all the changes on the canvas result in code changes.

You can also simply add the elements of the user interface in the usual way, with just a click on «+» and dragging the element to the canvases, but now we can drag it into the code directly.

Creating A List Of Posts

Let’s now try to create a list of posts, in case of using the old methods you would use the UITableView, but things are different now, let’s look in which way.

One of the ways is to use Stack, vertical, in this case. Let’s embed the text in Stack, Apple has added this function directly to the menu for more convenience. When clicking on a property while holding ⌘, do this and select «Embed in VStack».

Then copy the text a couple of times inside VStack and you’ll see the result, like in the picture below.

However, the second method — List is more convenient for the purpose.

Just change the VStack in the code to List and you’ll see something similar to UITableView — the elements will be found at the upper left of the list.

Let’s now make something more interesting from the post than a simple text field. Add a new SwiftUI View file for the purpose in the following way: choose File > New > File and name it «PostRow».

Add the following code to the body of the created file then:

// 1
VStack(alignment: .leading, spacing:10){// 2
            HStack {// 3	
                Image("userOne")
                    .resizable()
                    .clipShape(Circle())
                    .frame(width:50, height:50)// 4
                VStack(alignment: .leading){
                    Text("Maria Smith")
                        .font(.title)
                        .fontWeight(.bold)
                        .foregroundColor(.purple)
 
                    Text("Hello World!")}// 5
                Spacer()
 
                Text("11.10.2019")}
.padding(.horizontal, 10)// 6
            Image("one")
                .resizable()
                .frame(height:200)}

Let’s look into this code in more detail:

  1. Here a vertical stack with alignment on the left and with a distance between objects of 10 points is created.
  2. Horizontal Stack with horizontal spacing of 10 (this is done through the padding property, here you can specify any spacing)
  3. Add a picture with the author’s photo, resizable — narrow it down so that it fits into your frame, clipShape — make it round, frame — set the size.
  4. Vertical Stack with alignment on the left, with the name of the author and the name of the post in the middle.
  5. Spacer — fills in the empty space, after which the post date will be on the left side of the horizontal stack.
  6. A picture of the post with a height of 200.

And here’s what you’ve got:

The next step is to replace the ContentView structure with:

struct ContentView: View {
    var body: some View {
        List {
            PostRow()
            PostRow()
            PostRow()}.padding(.horizontal, -20)}}

Horizontal indentation is −20, so that the picture is adjacent to the corners, since List has its own embedded indentation, and unfortunately, there was no more elegant way to remove them at the time the article was written.

Now we have a list of the very nice posts. The next step is to make them dynamic.You have to do a bit of preparation for this.

1) Add a Swift file “Post” with the post entity:

import SwiftUI
 
struct Post: Codable, Identifiable {
    var firstName: String
    var lastName: String
    var title: String
    var avatar: String
    var photo: String
    var id: Int
    var date: String
    var description: String
 
    var fullName: String {return firstName +" "+ lastName
    }}

2) Add a Swift file “PostsData” with the information about the posts:

import UIKit
import SwiftUI
 
let posts:[Post]= getPosts()
 
private func getPosts()-> [Post]{return[
        Post(firstName:"Maria",
             lastName:"Holms",
             title:"Beautiful photo",
             avatar:"userOne",
             photo:"one",
             id:0,
             date:"10.11.2019",
             description:"Lorem ipsum dolor sit amet, eam ne tibique reformidans, mea ea quando fabellas persequeris. Sed fabulas voluptatum te. Petentium concludaturque et has, te quem appareat percipitur nec. Dignissim scriptorem ne qui, errem feugait ei vis, ut nam aeque referrentur."),
        Post(firstName:"Tom",
             lastName:"Riddle",
             title:"Crazy world",
             avatar:"userTwo",
             photo:"two",
             id:1,
             date:"10.11.2019",
             description:"Lorem ipsum dolor sit amet, eam ne tibique reformidans, mea ea quando fabellas persequeris. Sed fabulas voluptatum te. Petentium concludaturque et has, te quem appareat percipitur nec. Dignissim scriptorem ne qui, errem feugait ei vis, ut nam aeque referrentur."),
        Post(firstName:"Victor",
             lastName:"Tsoy",
             title:"Smile human being",
             avatar:"userThree",
             photo:"three",
             id:2,
             date:"10.11.2019",
             description:"Lorem ipsum dolor sit amet, eam ne tibique reformidans, mea ea quando fabellas persequeris. Sed fabulas voluptatum te. Petentium concludaturque et has, te quem appareat percipitur nec. Dignissim scriptorem ne qui, errem feugait ei vis, ut nam aeque referrentur.")]}

3) Change the PostRow file so that it takes data from the Post entity:

import SwiftUI
 
struct PostRow: View {
    var post: Post
 
    var body: some View {
        VStack(alignment: .leading, spacing:10){
            HStack {
                Image(post.avatar)
                    .resizable()
                    .clipShape(Circle())
                    .frame(width:50, height:50)
 
                VStack(alignment: .leading){
                    Text(post.fullName)
                        .font(.title)
                        .fontWeight(.bold)
                        .foregroundColor(.purple)
                    Text(post.title)}
                Spacer()
                Text(post.date)}.padding(.horizontal, 10)
            Image(post.photo)
                .resizable()
                .frame(height:200)
 
        }}}
 
struct PostRow_Previews: PreviewProvider {static var previews: some View {
        PostRow(post: posts[1])}}
 

4) Finally, change the ContentView to:

struct ContentView: View {
    var body: some View {
        List(posts, id: \.id){ post in
            PostRow(post: post)}
        .padding(.horizontal, -20)}}

Here you pass a list of posts to the List. It should also be noted that lists work with identifiable data. You can make your data identifiable in two ways: either by passing a key path to a property that uniquely identifies each element along with your data, or by matching your data type with the Identifiable protocol.

And here is what you’ll get:

Creating A Detailed View Of The Post

Now you move further and add the possibility to view the post by clicking on it. First of all, you should create a new SwiftUI file called "PostDetail":

import SwiftUI
 
struct PostDetail: View {
    var post: Post
 
    var body: some View {// 1
        ScrollView {// 2
            VStack {// 3
                Image(post.avatar)
                    .resizable()
                    .clipShape(Circle())
                    .overlay(
                        Circle().stroke(Color.black, lineWidth:2))
                    .shadow(radius:10)
                    .frame(height:300)
                    .offset(y:20)
                    .padding(.bottom, -300)// 4
                HStack(alignment: .top){
                    Text(post.firstName)
                        .font(.title)
                        .fontWeight(.bold)
                        .foregroundColor(Color.orange)
                    Spacer()
                    Text(post.lastName)
                        .font(.title)
                        .fontWeight(.bold)
                        .foregroundColor(Color.orange)}
                .padding()// 5
                Text(post.title)
                    .font(.title)
                    .fontWeight(.bold)
                    .padding(.top, 260)// 6
                Image(post.photo)
                    .resizable()
                    .frame(height:300)
 
                Text(post.description)}}}}struct PostDetail_Previews: PreviewProvider {static var previews: some View {
        PostDetail(post: posts[0])}}

Let’s look into this code in more detail:

  1. You create ScrollView so that a user can scroll your content.
  2. Vertical Stack is necessary, because scrolling should be vertical.
  3. Add a picture with the author’s photo with resizable properties — narrow it down so that it fits into the frame, clipShape — make it round, overlay — create a black bezel, shadow — add a shadow with a radius of 10, frame — set the height to 300, offset — step back by 20 points, padding — make a bottom indent of −300 so that the elements located below in the vertical stack do not take into account the avatar’s position.
  4. Horizontal Stack with text of the author’s name
  5. The text with the post title
  6. The picture of the post with a height of 300.

And looking at the canvas you’ll see:

Now you have to add navigation and with SwiftUI it’s not a problem at all.

Change the file ContentView:

struct ContentView: View {
    var body: some View {// 1
        NavigationView {
            List(posts, id: \.title){ post in// 2
                VStack {
                    PostRow(post: post)
                    NavigationLink(destination: PostDetail(post: post)){
                        EmptyView()}}}
            .padding(.horizontal, -20)// 3
            .navigationBarTitle(Text("Posts"))}}}
  1. Embed the list of posts into the NavigationView, it will add the NavigationBar in the upper part of the interface.
  2. Vertical Stack with the post and with the NavigationLink — passes to destination. You could also embed PostRow into the NavigationLink, but it would create disclosureIndicators on the right from the PostRow. That’s why you’ll put NavigationLink with an empty View into the Stack.
  3. Set the title NavigationBar in the «Posts».

That is all, now a when you click on the post you see its detailed view.

Conclusion

Let’s summarize, in this article you’ve got acquainted with a very cool technology SwiftUI, with its declarative syntax and interactive design creation. You have also created a small application using this wonderful technology. Now you can:

  • create a project with SwiftUI
  • create and change view
  • create lists and
  • transitions between screens

Swift UI — I really liked it, and it’s cool that this new road, though not yet perfect, has opened. I hope the article was useful and wish you good luck in your accomplishments.

You can find the full demo project on Bitbucket.