SwiftUI 2.0 - First Days

I’ve spent the last couple of weeks or so looking into SwiftUI 2.0 and wanted to document my thoughts about it while it was relatively fresh. Its often good to go back and look at early impressions of things to see how your thoughts or opinions changed.

I’m pretty happy with SwiftUI 2.0 - Apple added some new “native” components and fixed some things that I had developed work-arounds for; now those are obsolete. I looked through a list of the new features and created a simple App to learn about each new thing. Then I spent time upgrading my two apps (Journal and Password) to be SwiftUI 2.0 compliant; as of this writing I have not yet released them to the Apple App Store.

Impressions

This is a brief description of some of the new components available in SwiftUI 2.0 and how I made use of them.

Maps

The idea of a native Map component was something I was looking forward to using. I created my own MapView for SwiftUI 1.0 using UIViewRepresentable. With SwiftUI 2.0 the expectation was that I could toss that aside.

Alas, not so quick. While SwiftUI 2.0 comes with a nice implementation of MKMapView, it lacks interactivity that I need. You can place annotations (markers or pins) on the map, but they are not tappable. And there does not seem to be a way to get the user’s current location to indicate or track.

I decided to stick with my own MapView for now. I’m sure Apple will address this somehow. This was the only component I was disappointed with.

Grids

One thing lacking in SwiftUI 1.0 was a way to present collections in columns or rows. What people have done is wrap UICollectionView to do this. With the new LazyVGrid and LazyHGrid you do not need to do that. The “lazy” part of their names means they won’t create any children until they need to. Some folks call these virtualized lists.

Laying out a grid is easy: You create an array of GridItem instances that describe how many columns or rows there should be and how they should be sized (basically fixed or variable). Then you just fill them. If you need to scroll them, wrap them in a ScrollView. Each element that’s being presented should be given enough information to fill itself out. I used a LazyHGrid to present a strip of photos that were taken near a Journal entry’s location. As each thumbnail is exposed it requests a UIImage from the Photo library on the device, showing an activity spinner (ProgressView for SwiftUI 2.0) until the image is available.

Scrolling

Speaking of scrolling, one pretty irritating shortcoming in SwiftUI 1.0 was the inability to scroll to a specific element within a ScrollView. To solve that, SwiftUI 2.0 introduces ScrollViewReader which you place inside of a ScrollView. If you want to have a specific item brought into view, just give the ScrollViewReader its ID. If you place your request inside of a withAnimation block, the ScrollView will slide nicely right to the item.

I used this in my Journal app. When the app opens it shows a calendar. If you tap on a date, the next screen is a list of all of the entries in the month and it scrolls the view to the date you selected. In the SwiftUI 1.0 version I used a wrapped UITableView to accomplish that. Now I can discard that part to do this exclusively in SwiftUI 2.0. This really reduced the footprint of the app and it seems to be a bit quicker, too.

Tabs

You’re probably familiar with using a tabbed application: the bottom of the screen has icons and labels for different sections of the app. Facebook for example, has your home, market place, notifications, etc. Creating these with SwiftUI 2.0 and TabView is pretty easy.

There is however, something more that TabView can do for you: paging. You know those screens that have tiny dots at the bottom and you swipe left and right to go between them? Well by simply using the tabViewStyle modifier with TabView and giving it a PageTabViewStyle specifier, you turn your old tabs into pages. Pretty handy.

I used this with my Journal app to present a set of full-size images that might be associated with a journal entry. Once you tap on a thumbnail in the LazyHGrid, that action displays a new screen with the full size images. You can zoom and pan on them (like Instagram) or swipe to go to another image without returning to the previous screen to select a new image.

Final Thoughts

What impresses me most is that Apple really stuck with its view composition model. For example, the LazyHGrid does not scroll by itself. If you want that behavior, place it inside of a ScrollView. Likewise, you can add functionality with modifiers rather than having massive components with tons of options that you won’t use most of the time. Same goes for animation. The ScrollView will not slide to show you the item you want, you have to trigger it by placing your change inside of an animation block. This allows you to decide if you want the list to bounce into view, zip and slow down, take 2 minutes, etc.; it’s up to you.

I gave you a little taste of what is available in SwiftUI 2.0. I did not include changes to the Combine framework and Swift 5.3, but those were also welcome and I barely touched the surface of what’s capable there.

If you have been holding off going to SwiftUI, now is the best time to jump in. It is far more robust and capable than SwiftUI 1.0 - and I built a commercial app with that!

It’s so much easier and faster to build apps with SwiftUI. All of the tedium of layout constraints, actions, outlets, storyboards, XIB files, are - poof - gone.

And you do not have to go 100% into a re-write. Using the SwiftUI UIHostingController you can wrap SwiftUI components into your UIKit code. So if you have a new screen to develop that has animation or a tricky list layout, give SwiftUI 2.0 a try.

I will try and and do another one of these in a few months as I get more experience and we can compare notes.

Previous
Previous

SwiftUI and the Responder Chain

Next
Next

Simple Charts with SwiftUI