Using Focus API’s in SwiftUI
What is Focus
- This is a tool to decide how to respond when someone interacts with an input method. On their own they don’t provide enough information on which onscreen control to interact with.
- When a view has focus, the system will use it as a starting point to react to input
- It has a border on macOS, watchOS has a green border, and on tvOS it will hover above the UI
- Helps users understand where input will go, it’s a special kind of cursor
- It is a cursor for the user’s attention
Ingredients
- Focusable views
- Different views are focusable for different reasons. Text fields are always focusable. Buttons are used for clicks and taps, you need keyboard navigation system wide to allow for buttons to be tab able.
- Buttons support focus for activation. In iOS 17 and macOS Sonoma – there are new view modifier to define the types of interactions you support. .focusable(interactions: .edit) or .focusable(interactions: .activate). If you don’t define an interaction, you will get the .all value. Prior to macOS Sonoma the system only used .activate focus modifier. (I should add focusable in my code)
- Focus state
- The system keeps track of which view has focus – this is @FocusState bindings -it is a bool (or custom data types for more complex interactions)
- Views can read this to understand when they are in focus or not.
- Focused values
- This solves data dependencies that link remote parts of your application. This is like using a custom environment key and values. Set up a getter and setter, and define view Modifiers to address this
- Focus sections
- Gives you a way to influence how things move when people swipe on a remote or hit tab on a keyboard. This follows the layout order of the locale on a keyboard. But directional on Apple TV remote.
- You use .focusSection() to guide focus to the nearest focusable content. You will need to add spacers to align content.
Recipes
- For custom controls you should consider which items to focus on when lists appear. The Grocery list example in this session explains how to do this with @FocusState and .defaultFocus()
- If you want the app to move focus programmatically you can use the same example of adding a new item to the list
- I should address focus in my Wasted Time app for updates on the settings screen
- If you create a custom control, the custom picker example helps with this pattern.
- Remember to turn on Keyboard navigation systemwide
- Focusable grid view is the final receipt – using Lazy Grid