UIKit layouts in Swift Playgrounds for iPad

Exploring iOS 10 (beta 2)

In this post I’m going to further explore the new iPad Swift Playgrounds app, currently available with the beta of iOS 10. As with the previous post, I’m focussing on what iPad Playgrounds is like as a tool for developing code, starting from the in-app blank playground template, and building a responsive UIKit interface. At the end I will touch on creating Playgrounds on the Mac in the new Playgrounds Book format, and bringing those onto the iPad.

A simple UIKit layout with UIStackView

As I mentioned in the previous post, starting with Xcode 7.3, Playgrounds in Xcode, and now on the iPad with the iOS 10 beta, have been able to deal with user interactions. To do this, import PlaygroundSupport, and set PlaygroundPage.current.liveView to an instance of a UIView or UIViewController, or any subclass thereof:

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    override func viewDidLoad(){
        super.viewDidLoad()
        title = "Hello UIKit"
        // lay out your view here
    }

}

let controller = ViewController()

PlaygroundPage.current.liveView = UINavigationController(rootViewController: controller)

Here, I’ve subclassed UIViewController and wrapped in a UINavigationController, as this gives us the title bar, and an easy way to add a couple of buttons either side of the bar.

For very simple apps, this might be all the layout they need. But what about more complex layouts? Playgrounds doesn’t come with Xcode’s developer tools such as interface builder or the various scene editors. If you’re mocking up a UIKit layout in iPad playgrounds then, you’re going to have to write the layout programmatically. One nice way of laying out elements without too much hassle is with UIStackView, introduced in iOS 9. You add sub-views to the stackview, then declare which axis you want it to be aligned on, how you want the items to be spaced out and so on. Complex layouts can be built up quickly by nesting stack views inside one another.

One of the nice things about iPad Playgrounds is how you can change the size of the liveView window, from split-view to full screen, in both landscape and portrait orientations. In landscape mode, this mimics the split-screen feature that was introduced in iOS 9, although Playgrounds is restricted to a 50-50 view. The one-third split-screen view isn’t available, nor is the vertical split-screen in portrait orientation (in Playgrounds, the view splits horizontally when you hold the iPad in portait mode). Nevertheless, the Playgrounds app gives us a couple of different sizes and orientations, so could be a nice way to quickly mock up a layout.

To give this a go, I wrote an app that allows you to explore the new GameplayKit procedural noise generation functions that are being added in iOS 10. To explore the various noise settings, it provides a simple single-view interface, laid out with nested stack views (thoughts on the new noise functions will come in a later post). I also added a pan gesture recognizer to allow the user to pan around the noise field by dragging with one finger, and (on iOS only) to move “through” the noise by dragging two fingers vertically. Here’s the source code for the Playground.

It looks pretty good as a static view. However, a UIStackView only becomes “responsive”, dynamically changing the layout depending on the dimensions of the view, typically by switching the layout between horizontal and vertical depending on available space, if it can read and react to the size of the containing frame. In order for a UIStackView to dynamically react to changes in frame size, you can subclass UIViewController and override the viewDidLayoutSubviews method of the view controller. This method is decribed by FlexMonkey in this blog post on UIStackView.

In the GameplayKit Noise Explorer playground running in iPad Playgrounds, when you switch the live view window into landscape split screen, the sliders and the stepper in the control panel are stacked in a 2-by-2 formation. When you go full-screen though, the control panel switches to the horizontal axis, laying them out in a row. Note that this rearranging only works in the iPad version of Playgrounds. If you run the code in Xcode 8 beta, the simulator in the live view seems to stay locked to an iPhone-sized window in portrait orientation, regardless of how you resize the live window.

The new Playgrounds Book Package format

I’ve been emphasizing how this could be a useful way to mock up an interface in native code, on the iPad. But, if you look at the screenshots in this post, you’ll see that the live view window of the iPad playgrounds coded from the blank template has a blurred border going around it, presumably to separate the live view from the coding pane, and to isolate the Run code/ Stop button. But this border is kind of annoying if we want an environment that resembles some of the formats that our interface might run in if it left the mock-up stage and were an actual app.

Is there some way to get rid of that border? Programmatically, in-app, no, not that I’ve found so far. However, it is possible to remove the border if you create a Playground in the new Playground Book Package format, and send that over to iPad Playgrounds (for instance, using AirDrop from a Mac). On the Apple dev site, there is a small amount of documentation on the Playground Book format, and an empty template, but a far better source is to export all the Playground books that are in the iPad app using the share pane (at the time of writing, there are 3 featured playgrounds, plus the 2 created by the Answers and Shapes templates) and have a look at what they are doing (Thanks to Erica Sadun for pointing out that the built-in Playground Books can be exported in this way. I wonder whether the book package format will always be as open as this, or will content become more locked down once iOS 10 leaves beta?). To get a full-screen edge-to-edge liveview, it’s just a matter of setting a single key in the page’s Manifest.plist:

    <key>LiveViewEdgeToEdge</key>
    <true/>

Send the Playground Book package back over to the iPad (the book package format doesn’t effect Xcode playgrounds), and when you open it up, you’ll have an edge-to-edge live-view. It’s easy to see now why Apple added the border, as in this example it’s hard to see the join between the coding pane and the live view:

When you create a new playground in the iPad app, a modal appears asking you to choose from 2 templates (Answers or Shapes), or create a blank playground. I haven’t yet found out if there’s a way to add extra templates to this menu using the Book Package format. This would certainly be a very nice feature to have. As a work-around though, the Book Package format can be used as a way to implement a template. You could add some boilerplate code in the Contents.swift file, or set some keys in the plist as I’ve done here. Playgrounds created in the Book Package format have a “reset page” option, so when you want a new instance of that “template”, you’d duplicate the playground in the iPad app, then hit the reset button to start working from the boilerplate.

In my explorations so far, UIKit seems to be working pretty well. Next up, I’ll look at SpriteKit and SceneKit in iPad Playgrounds where, as of writing (beta 2), the news isn’t so rosy (update: SpriteKit and SceneKit now run very well in beta 4).

Built with Jekyll      © Salt Pig Media