SwiftUI in Playground tips and tricks

SwiftUI in Playground tips and tricks

Perhaps by now you have read lots of articles about SwiftUI, and if you were lucky, you have had the chance to start a small project and get to know it. For me learning and trying new APIs starts from Playground, not Xcode. So despite all other tutorials I am going to point out some cool features of SwiftUI using Playground.

This article contains some basics and tips with examples which I mostly learned at Swift Island Conference 2019 from Erica Sadun.


It is a beginner’s guide to try SwiftUI components in Xcode Playground :)


What is SwiftUI?

SwiftUI is a new/simple way to build user interfaces across all Apple platforms. You all know the differences between building UI in code vs in Interface builder. SwiftUI is a declarative approach to build UI that covers the flaws of the Imperative approach.

Declarative vs. Imperative

In the Declarative way of building UI you can easily describe what you expect from your user interface, and the code will follow your state. In Imperative approaches(before SwiftUI) you should implement all the steps. For example, you want to show a welcome message after the user is logged in and a goodbye message when the user is logged out. We know this situation as “State”. Being Logged in or Logged out is an authentication state. In the Imperative way of coding you need to write code to manage the changes of state, but in the Declarative way SwiftUI will do it for you.

Now let’s see how you can write the famous “Hello World” on the screen in both the Declarative and theImperative way.

The familiar Imperative way is:

And the Declarative SwiftUI:

But what if you don’t want to use the struct and only want to play around with the new structures like Text itself.

let text = Text("Hello, World")

in this case the result will be:

This is not as declarative and representative as it should be. To overcome this problem I am using the following extensions to get us a better look of what we are doing. (Just copy and paste it in your project)

extension UIView {
/// Renders the view layer to a new UIImage.
public var renderedImage: UIImage {
    let image = UIGraphicsImageRenderer(size: self.bounds.size)
        .image { context in
           UIColor.lightGray.set(); UIRectFill(bounds)
           context.cgContext.setAlpha(0.75)
           self.layer.render(in: context.cgContext)
     }
    return image
  }
}


extension View {
/// Renders a SwiftUI View to a UIImage, primarily for direct preview
/// in the Swift playground.
  public var renderedImage: UIImage {
      let (tWidth, tHeight) = (CGFloat(320.0), CGFloat(160.0))
      let frame = CGRect(origin: .zero,
                        size: CGSize(width: tWidth, height: tHeight))
      let window = UIWindow(frame: frame) 
      let hosting = UIHostingController(rootView: self)
      hosting.view.frame = window.frame 
      window.rootViewController = hosting
      window.makeKey()
      return hosting.view.renderedImage
   }
}

So now if you run the code one more time and press the preview button you’ll get the image of the Text.

let text = Text("Hello, World").renderedImage

Now you can expend your experiment and add more details to Text, like padding, font, foregroundColor and background Color:

To add styles like background color, Text color and Font in an Imperative way, I added a func named “setupStyle()”:

private func setupStyle() {
   label.backgroundColor = .yellow
   label.textColor = .red
   label.font = UIFont.systemFont(ofSize: 12, weight: .bold)
}

But in the Declarative way you can easily add them to the “Text” right away.

See how easy it is to add the default padding?!

There is an important tip here. 

.background(Color.black)

background color is not of type Color anymore, It is View.

To show you what it means, try to add cornerRadius to the Text:

It’s easy, right?

But in swiftUI you can add this cornerRadius to backgroundColor since it’s a view.

and here is the result:


Read the user input in TextField and open keyboard in Playground

Let’s talk about the state variable. State variable is a rescue of all state(value we save) problems in our apps. It keeps track of the current state and all the changes. 

@State var text: String = ""

Now “text” is going to save the user input in textField and all the changes like:

TextField($text, placeholder: Text("Name"))

To show a textField with Name(UILabel in UIKit and Text in SwiftUI) we need a struct with Horizontal Stack which is nested in Vertical Stack.

struct LiveView: View {
   @State var text: String = "" 
   var body: some View {
        VStack {
          HStack {
               Text("Name:")
               TextField($text, placeholder: Text("Name"))
              }
              .padding()
          if !text.isEmpty {
             Text("Hello \(text)")
          }
       }
    }
}

Now if you are interested in opening the keyboard in playground, set the hostingController as RootViewController:

let size = CGSize(width: 1024, height: 1024)
let frame = CGRect(origin: .zero, size: size)
let hosting = UIHostingController(rootView: LiveView())
hosting.view.frame = frame
hosting.view.backgroundColor = .white
let window = UIWindow(frame: frame)
window.rootViewController = hosting
window.makeKeyAndVisible()


PlaygroundPage.current.liveView = window

The first look will be:

But you need to make more space for the simulator by pulling the separator window to the right.

Here is the final result.

As a gift, since you have arrived at this step, you can easily access Simulator Settings in playground by pressing the emoji button and open Keyboard Settings:


All in all, Implementing UI with SwiftUI is a new approach which gives you the benefit of both building UI in code an having the visual at the same time.

Leave a Reply

Close Menu