Secret SwiftUI: A practical use for _VariadicView
I’m kind of late to the party on this, frankly. _VariadicView helps us create custom VStacks. Our own flexible tab bars. Bespoke pickers and lists. I started writing this article in March 2024, but was stumped trying to find a non-contrived example—one that would actually be useful in production. While mulling it over on a mental background thread, this article faded into a dusty backlog alongside aborted magnum opi such as Through The Ages: Apple Concurrency APIs and Dumb Ways To Maximise Your App Binary Size. Recently, that all changed. At midnight, I was doing what we all do once our wives fall asleep: reading Vincent Pradeilles. Specifically, his article on building inverted scroll for messaging apps. Inspiration struck. I finally realised a practical use case for _VariadicView: a reusable Today, much like our scrolling, let’s work backwards. We’ll implement a scroll inversion, and experience the pain point together as our UI grows more complicated. Only then will I introduce _VariadicView, take you under the covers to explain how it all works, then demonstrate how you can use _VariadicView to address this specific pain point in your own apps. Building an Inverted ScrollInverted chat scroll is the cornerstone of messaging app UX. It’s just a scroll view that starts at the bottom (with the newest messages), so the user scrolls up to see older content. This differs from the standard scrolling feed UX, where you start at the top of the screen and scroll down for more content. The trick to implementing this is deceptively simple: you flip the scroll view so it’s upside down. This can be done with 2 lines of SwiftUI modifiers:
Applied to a List view, this gives us the “start at the bottom and scroll up” effect we want, however the chat message content is also inverted! To fix this, we have to apply the same vertical inversion individually to all the pieces of content. This leaves your view looking a little like this:
This does the job, but becomes unwieldy and error-prone as you bring your chat app up to parity with iMessage. As more types of view are implemented like messages, date headers, and text fields, this gets messy fast.
Enter: _VariadicView. WTF is a _VariadicView?_VariadicView is a private-ish SwiftUI API, and the underlying implementation detail for many of the container views you use every day. It sounds pretty obscure, however its naming is actually pretty straightforward: it’s a view that can be passed any number of views, hence variadic. _VariadicView lets you do one thing well:
Despite being an underscored “private” API, it’s safe to use in production—many How to use _VariadicViewWe want to set up a simple container for all our chat content that handles the inversion automatically. We want to implement this once, then apply the inverted scrolling for free anytime we like. _VariadicView.TreeWe start by creating this container view: ChatList.
We initialise this view with content—the child views, such as messages, passed into the ChatList container. The body declares a _VariadicView.Tree. This represents a SwiftUI view tree which can be rendered by the layout engine. The API declaration looks like this:
We pass in a Layout that conforms to _VariadicView_MultiViewRoot and content—the child views passed into our container. _VariadicView_MultiViewRootNow, we can implement this Layout. This is where the magic happens.
The body of a _VariadicView_MultiViewRoot is the root of the SwiftUI view tree hierarchy. It lays out the child views that represent the leaf nodes in this view hierarchy. This gives us a new power not present in vanilla SwiftUI code: we can declare a container view with child views, and perform modifications to, or between, each child view without the parent knowing. In short:
This means our container can wrap functionality like inverting a scroll, and re-inverting each child view individually. Instead of leaking this complexity into the top-level view every time we touch the list, this inversion becomes an implementation detail—we can hide this complexity in the container. The devs adding new chat functionality or polishing the UI may never know about it. _VariadicView.ChildrenInside the body, we have some pretty standard SwiftUI code to represent a scrolling list, set basic styling, and vertically invert all the content. _VariadicView.Children represents the content in our ChatList—the child views passed into our container. This conforms to RandomAccessCollection, Identifiable, and View. This means we can iterate through and render each child, even subscripting them if we want further individual customisation. Putting It All TogetherNow that we’ve created our ChatList container, let’s see it in action.
ChatList internally handles the UI inversion, so we can focus fully on building a sick messaging app for our users! Despite being the best example I could find in 11 months, this approach isn’t limited to Chat UIs. Any dynamic container, carousel, or list can apply _VariadicView to create flexible components to delight your colleagues and end-users. If you’re still confused about _VariadicView, that’s because it’s confusing. The key takeaway is that _VariadicView allows you to do create containers that do stuff between their root and leaf nodes. In practical, concrete, non-jargony terms, _VariadicView is occasionally quite useful when you want to wrap some annoying domain-specific boilerplate in a component. If you want to check out the whole project, goto _Secret_SwiftUI on Github.
|