The SwiftUI cookbook for focus - WWDC23 - Videos - Apple Developer

<aside> ⚠️ El focus es el sistema con el que podemos configurar el comportamiento para el teclado en mac, la corona en el apple watch o el swipe en el Apple TV. Es como un cursor para la atención del usuario

</aside>

Ingredients

Focusables views

struct RecipeGrid: View {
    var body: some View {
        LazyVGrid(columns: [GridItem(), GridItem()]) {
            ForEach(0..<4) { _ in Capsule() }
        }
        .focusable(interactions: .edit)
    }
}

struct RatingPicker: View {
    var body: some View {
        HStack { Capsule() ; Capsule() }
            .focusable(interactions: .activate)
    }
}

El focusable on activate recibirá el foco si el keyboard navigation está activado.Con el contentShape capsule podemos definir que su forma sea la de una cápsula para que el foco tome esa forma.

El focusable on activate recibirá el foco si el keyboard navigation está activado.Con el contentShape capsule podemos definir que su forma sea la de una cápsula para que el foco tome esa forma.

Focus State

struct GroceryListView: View {
    @FocusState private var isItemFocused
    @State private var itemName = ""

    var body: some View {
        TextField("Item Name", text: $itemName)
            .focused($isItemFocused)

        Button("Done") { isItemFocused = false }
            .disabled(!isItemFocused)
    }
}

Focused values

struct SelectedRecipeKey: FocusedValueKey {
    typealias Value = Binding<Recipe>
}

extension FocusedValues {
    var selectedRecipe: Binding<Recipe>? {
        get { self[SelectedRecipeKey.self] }
        set { self[SelectedRecipeKey.self] = newValue }
    }
} 

struct RecipeView: View {
    @Binding var recipe: Recipe

    var body: some View {
        VStack {
            Text(recipe.title)
        }
        .focusedSceneValue(\\.selectedRecipe, $recipe)
    }
}

struct RecipeCommands: Commands {
    @FocusedBinding(\\.selectedRecipe) private var selectedRecipe: Recipe?

    var body: some Commands {
        CommandMenu("Recipe") {
            Button("Add to Grocery List") {
                if let selectedRecipe {
                    addRecipe(selectedRecipe)
                }
            }
            .disabled(selectedRecipe == nil)
        }
    }

    private func addRecipe(_ recipe: Recipe) { /* ... */ }
}

struct Recipe: Hashable, Identifiable {
    let id = UUID()
    var title = ""
    var isFavorite = false
}

Aquí un ejemplo del focused value en un LazyVGrid que nos permite gestionar con el teclado el

Aquí un ejemplo del focused value en un LazyVGrid que nos permite gestionar con el teclado el

Este nuevo método nos permite capturar las teclas que se han pulsado con el foco encima

Este nuevo método nos permite capturar las teclas que se han pulsado con el foco encima

Focus sections

Los focus section permiten mover el foco hacia secciones enteras nuevas, similar a como funciona en apple tv.

struct ContentView: View {
    @State private var favorites = Recipe.examples
    @State private var selection = Recipe.examples.first!
 
    var body: some View {
        VStack {
            HStack {
                ForEach(favorites) { recipe in
                    Button(recipe.name) { selection = recipe }
                }
            }

            Image(selection.imageName)

            HStack {
                Spacer()
                Button("Add to Grocery List") { addIngredients(selection) }
                Spacer()
            }
            .focusSection()
        }
    }

    private func addIngredients(_ recipe: Recipe) { /* ... */ }
}

struct Recipe: Hashable, Identifiable {
    static let examples: [Recipe] = [
        Recipe(name: "Apple Pie"),
        Recipe(name: "Baklava"),
        Recipe(name: "Crème Brûlée")
    ]

    let id = UUID()
    var name = ""
    var imageName = ""
}