The missing UIFocusGuide for SwiftUI
Although Apple added some limited focus support in 2020 (WWDC20-10042), it is still lacking behind it's UIFocusGuide
counterpart.
- iOS 14.0 or greater
- tvOS 14.0 or greater
- macOS 10.15 or greater
import SwiftUI
import SwiftUIFocusGuide
struct SimpleExampleView: View {
@StateObject var focusBag = SwiftUIFocusBag()
var body: some View {
HStack(spacing: 0) {
VStack {
Button(action: {}, label: { Text("Button") })
Spacer()
}
.addFocusGuide(using: focusBag, name: "Left", destinations: [.right: "Right"], debug: true)
VStack {
Spacer()
Button(action: {}, label: { Text("Button") })
}
.addFocusGuide(using: focusBag, name: "Right", destinations: [.left: "Left"], debug: true)
}
}
}
The above example looks like this:
Passing debug: true
visualizes the focus guides on the screen.
A more complex example can be found in the Example tvOS app.
SwiftUIFocusGuide
wraps its content in a UIHostingController
and setups a focus guide for each direction. It then sets the preferredFocusEnvironments
according to the specified destination by name.
public func updateUIViewController(_ uiViewController: UIHostingController<Content>, context: Context) {
...
for (direction, destination) in destinations {
...
if let destinationView = bag.views[destination.name] {
context.coordinator.guides[direction]?.preferredFocusEnvironments = bag.isEnabled ? [destinationView] : []
}
}
}
For a deeper understanding of how UIFocusGuide
works, I recommend this article.
Using UIHostingController
has its caveats: It does not wrap its intrinsic content size. As a result, the focus guide takes up all available space. You would have to set a fixed size with the frame()
modifier and set its intrinsic content size manually.
See: