Adjust your app’s behavior and filter incoming notifications based on the user's Focus settings.

Posts under Focus tag

10 Posts

Post

Replies

Boosts

Views

Activity

UIHostingConfiguration focus problem on tvOS, with SwiftUI view
UIHostingConfiguration on tvOS: focus permanently broken with multiple focusable SwiftUI views Hi everyone, I'm working on a tvOS app with a UICollectionView. Some cells embed SwiftUI content via UIHostingConfiguration, specifically a row of 3 buttons that should be individually focusable. The cell itself returns canBecomeFocused = false so focus passes through to the SwiftUI buttons. The problem: after navigating focus into that section once, it becomes permanently unfocusable. Focus enters briefly, then immediately exits to nil on its own, without any user input. From that point on, the focus engine completely skips the section. The exact same SwiftUI view works perfectly when embedded via UIHostingController instead. How to reproduce Press DOWN to move focus into the UIHostingConfiguration section Focus lands on a SwiftUI button for a split second Focus exits on its own and bumps to another section The section is now dead, focus skips it on every subsequent navigation What the system logs say (-UIFocusLoggingEnabled YES) Right when focus enters, the system reports the SwiftUI focus items as "disappearing": Ignoring focus update request for disappearing focus environment <UIKitFocusSectionResponderItem> Then when searching for a new focusable item: <SwiftUI._UIInheritedView> → (warning) No focusable items found. <UIHostingContentView> → (warning) No focusable items found. === unable to find focused item in context. retrying with updated request. === The views are still in the hierarchy (verified by pointer), but the UIHostingContentView no longer exposes its virtual focus items. I also see mismatched parentFocusEnvironment on those items, pointing to a _UIHostingView from a completely different cell. What I've tried I've spent a lot of time on this with my colleagues, dug through the very limited documentation available online, and even used AI agents to help brainstorm. We tested 10 different approaches, none worked: Overriding preferredFocusEnvironments to point to the UIHostingContentView setNeedsFocusUpdate() / updateFocusIfNeeded(), rescan finds nothing Forcing UIKit redraws (setNeedsLayout, setNeedsDisplay) Removing .focusSection() Removing all SwiftUI animations, identical behavior Using canFocusItemAt: delegate instead of cell subclass, identical remembersLastFocusedIndexPath = true, causes a separate focus trap configurationUpdateHandler + setNeedsUpdateConfiguration(), config is rebuilt but virtual items stay deregistered Verified the UIHostingContentView never leaves the hierarchy. It doesn't, its internal state is just corrupted My workaround I switched to UIHostingController with proper view controller containment. It works because the hosting controller is a full UIFocusEnvironment, so the focus engine can traverse it and it correctly maintains its virtual items. Has anyone encountered this? Is there a known pattern for using UIHostingConfiguration on tvOS with multiple focusable SwiftUI elements? Or should I just file a Feedback? Thanks for any help!
1
0
16
2d
SetFocusFilterIntent app cannot be copied to another Mac
I have recently added a SetFocusFilterIntent target extension to my app which is a system utility which goes into the menu bar(Application is agent = YES). I have followed the approach in the WWDC22 video introducing Focus Intent and I have created an App Groups to being able to make the Extension to communicate with my main app, however from when I did this sometimes when I run the app I do get this log line: Couldn't read values in CFPrefsPlistSource<0x97cd34700> (Domain: group.xxx.xxx.MyApp, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd Despite this the Focus mode integration is working correctly on my development Mac. However I used to Archive the app and then Copy the app to my MacBook but when I do that now my other Mac cannot open the app and it is giving me an error. If I revert this change then I can bring the app back to my other Mac as usual following the procedure: Product -> Archive. Then from the archiver: Distribute App -> Copy App. After that I copy the app generated to the App folder of my other MacBook but it doesn't open anymore. During the archival phase now I am even getting this warning: MyAppFocus.appex is an ExtensionKit extension and must be embedded in the parent app bundle's Extensions directory, but is embedded in the parent app bundle's ../../../BuildProductsPath/Release/MyApp.app/Contents/Extensions directory. How can I solve this issue? If I rollback the commit related to this SetFocusFilterIntent new feature the app can be Copied and moved to the other Mac as before. Is this related to the extension or to the fact that I had to use this new entitlement: com.apple.security.application-groups ?
0
1
185
Dec ’25
Notification easy control
Dear Apple Team, I hope this message finds you well. I wanted to share a playful and innovative idea that could enhance the iPhone experience—particularly when viewing content in full-screen mode through apps like Apple TV or YouTube. Feature Concept: Hands-Free Dismissal of Notifications When the iPhone is in landscape mode, incoming notifications can interrupt the viewing experience. While Focus Mode and swipe gestures help, I thought of a more intuitive and hands-free interaction: using a light puff of air directed toward the screen to dismiss a notification. This interaction could use the microphone or other onboard sensors to detect a brief burst of air, providing a fun and natural way to maintain immersion without touching the device. If this isn’t feasible with current hardware, here are a few alternative concepts that align with the same goal: Blink to Dismiss: Using Face ID sensors to detect a quick blink as a hands-free gesture. Shake to Dismiss: A gentle shake gesture when holding the iPhone in one hand. Gaze-Based Dismissal: Notifications automatically disappear after a brief moment of eye contact. These ideas could offer both accessibility benefits and a touch of delight—making the iPhone feel even more magical and responsive. Thank you for your time and for considering this suggestion! Warm regards, Badhan Baidya
1
0
133
Sep ’25
How to disable the default focus effect and detect keyboard focus in SwiftUI?
I’m trying to customize the keyboard focus appearance in SwiftUI. In UIKit (see WWDC 2021 session Focus on iPad keyboard navigation), it’s possible to remove the default UIFocusHaloEffect and change a view’s appearance depending on whether it has focus or not. In SwiftUI I’ve tried the following: .focusable() // .focusable(true, interactions: .activate) .focusEffectDisabled() .focused($isFocused) However, I’m running into several issues: .focusable(true, interactions: .activate) causes an infinite loop, so keyboard navigation stops responding .focusEffectDisabled() doesn’t seem to remove the default focus effect on iOS Using @FocusState prevents Space from triggering the action when the view has keyboard focus My main questions: How can I reliably detect whether a SwiftUI view has keyboard focus? (Is there an alternative to FocusState that integrates better with keyboard navigation on iOS?) What’s the recommended way in SwiftUI to disable the default focus effect (the blue overlay) and replace it with a custom border? Any guidance or best practices would be greatly appreciated! Here's my sample code: import SwiftUI struct KeyboardFocusExample: View { var body: some View { // The ScrollView is required, otherwise the custom focus value resets to false after a few seconds. I also need it for my actual use case ScrollView { VStack { Text("First button") .keyboardFocus() .button { print("First button tapped") } Text("Second button") .keyboardFocus() .button { print("Second button tapped") } } } } } // MARK: - Focus Modifier struct KeyboardFocusModifier: ViewModifier { @FocusState private var isFocused: Bool func body(content: Content) -> some View { content .focusable() // ⚠️ Must come before .focused(), otherwise the FocusState won’t be recognized // .focusable(true, interactions: .activate) // ⚠️ This causes an infinite loop, so keyboard navigation no longer responds .focusEffectDisabled() // ⚠️ Has no effect on iOS .focused($isFocused) // Custom Halo effect .padding(4) .overlay( RoundedRectangle(cornerRadius: 18) .strokeBorder( isFocused ? .red : .clear, lineWidth: 2 ) ) .padding(-4) } } extension View { public func keyboardFocus() -> some View { modifier(KeyboardFocusModifier()) } } // MARK: - Button Modifier /// ⚠️ Using a Button view makes no difference struct ButtonModifier: ViewModifier { let action: () -> Void func body(content: Content) -> some View { content .contentShape(Rectangle()) .onTapGesture { action() } .accessibilityAction { action() } .accessibilityAddTraits(.isButton) .accessibilityElement(children: .combine) .accessibilityRespondsToUserInteraction() } } extension View { public func button(action: @escaping () -> Void) -> some View { modifier(ButtonModifier(action: action)) } }
1
0
514
Sep ’25
FocusedBinding and selecting item in the List issue
Hello dear community! I'm still new to SwiftUI and going through the official Introducing SwiftUI Tutorials (basically, building the Landmarks app) And I'm struggle with some behavior I noticed in the macOS version of the Landmarks app. So, here is the idea, there is a list of Landmarks (the simplified version from the tutorial): struct LandmarkList: View { @Environment(ModelData.self) var modelData @State private var selectedLandmark: Landmark? var index: Int? { modelData.landmarks.firstIndex(where: { $0.id == selectedLandmark?.id }) } var body: some View { @Bindable var modelData = modelData NavigationSplitView { List(selection: $selectedLandmark) { ForEach(modelData.landmarks) { landmark in NavigationLink { LandmarkDetail(landmark: landmark) } label: { LandmarkRow(landmark: landmark) } .tag(landmark) } } .navigationTitle("Landmarks") .frame(minWidth: 300) } detail: { Text("Select a landmark") } .focusedValue(\.selectedLandmark, $modelData.landmarks[index ?? 0]) } } And there are a few helper structs which makes the possibility of the Marking a selected landmark as favorite (or remove) via shortcut and via menu: struct LandmarkCommands: Commands { @FocusedBinding(\.selectedLandmark) var selectedLandmark var body: some Commands { SidebarCommands() CommandMenu("Landmark") { Button("\(selectedLandmark?.isFavorite == true ? "Remove" : "Mark") as Favorite") { selectedLandmark?.isFavorite.toggle() } .keyboardShortcut("f", modifiers: [.shift, .option]) .disabled(selectedLandmark == nil) } } } private struct SelectedLandmarkKey: FocusedValueKey { typealias Value = Binding<Landmark> } extension FocusedValues { var selectedLandmark: Binding<Landmark>? { get { self[SelectedLandmarkKey.self] } set { self[SelectedLandmarkKey.self] = newValue } } } So, with this setup which is presented in the tutorial I notice 3 issues: On the first launch of the app, if I try to select a landmark — it's get unselected instantly. It I try to select it again — it works Marking a selected Landmark as favorite via shortcut (f+shift+opt) or via menu makes the selected Landmark unselected On the Landmark details — marking a Landmark as Favorite also makes the landmark unselected. You can check it on your own if you download the completed project from this page: https://developer.apple.com/tutorials/swiftui/creating-a-macos-app But could someone please explain why it's happening? And how to avoid such a bad UX with unselecting items in the list?
Topic: UI Frameworks SubTopic: SwiftUI Tags:
1
0
219
Jul ’25
Notification interruptions
My app Balletrax is a music player for people to use while they teach ballet. Used to be you could silence notifications during use, but now the customer seems to have to know how to use Focus mode, remember to turn it on and off, and have to check the notifications one does and doesn't want to use. Is there no way to silence all notifications when the app is in use?
0
0
93
Apr ’25
VisionOS - Gamepad steals focus
I am developing a vision os app for controlling an underwater ROV. I have ornaments with telemetry and buttons around a central video view feed. I have custom buttons mappings, such as "A" for locking the depth of the drone. However, when I look at buttons or certain ornaments, my custom gamepad logic is kept from running. This means that when a SwiftUI Button gains focus on visionOS, pressing the controller’s A button triggers the system’s default “click” on that Button rather than my custom buttonA handler. Essentially, focus interception by the system is stealing my A-press events and preventing my custom gamepad logic from running. Is there a way to disable the built in gamepad interaction and only allow my custom gamepad mappings?
1
0
238
Apr ’25
SetFocusFilterIntent `perform()` method is not called on iOS 18 beta
I’ve set up a focus filter, but the perform() method in SetFocusFilterIntent isn't called when the focus mode is toggled on or off on my iPhone since I updated to iOS 18 beta (22A5326f). I can reproduce the issue for my app, but focus filters are also broken for any third-party apps installed on my phone, so I guess it's not specific to how I've implemented my filter intent. This used to work perfectly on iOS 17. I didn't change a single line of code, and it broke completely on the latest iOS 18 beta. I've filed a bug report including a sysdiagnose (FB14715113). To the developers out there, is this something you are also observing in your apps?
3
0
776
Mar ’25
SwiftUI: TextField not getting focus changes inside Button
I have a SwiftUI List (on macOS) where I want to display a few TextFields in each row, and observe how the focus changes as an individual text field is selected or unselected. This seems to work fine if I just have the List display a pure TextField in each row, but if I embed the TextField inside a Button view, the focus change notifications stop working. I want the 'button' functionality so that the user can tap anywhere on the row and have the text field activated, instead of tapping exactly on the text field boundary. Here is some code to demonstrate the problem. In the List if you have RowView uncommented out (1), then the focus change notifications work. If you comment that out and uncomment the RowViewWithButton (2), then the button functionality works, but I can't get focus change notifications anymore. Here is the code to reproduce the issue. Interestingly, when I test this on iOS, it works fine in both cases. But I need the solution for macOS. import SwiftUI // test on macOS target struct ContentView: View { @State private var textFields = Array(repeating: "", count: 4) @FocusState private var focusedField: Int? var body: some View { List(0..<4, id: \.self) { index in // 1. works with focus notification changes RowView(index: index, text: $textFields[index], focusedField: $focusedField) // 2. button works, but no focus notifications on text field //RowViewWithButton(index: index, text: $textFields[index], focusedField: $focusedField) } } } struct RowView: View { let index: Int @Binding var text: String @FocusState.Binding var focusedField: Int? var body: some View { HStack { Text("Row \(index + 1):") TextField("", text: $text) .multilineTextAlignment(.leading) .focused($focusedField, equals: index) } .onChange(of: focusedField) { newFocus in if newFocus == index { print("TextField \(index) is in focus") } else { print("TextField \(index) lost focus") } } .padding(.vertical, 4) } } struct RowViewWithButton: View { let index: Int @Binding var text: String @FocusState.Binding var focusedField: Int? var body: some View { Button (action: { print("RowView - button selected at index \(index)") focusedField = index }) { HStack { Text("Row \(index + 1):") TextField("", text: $text) .multilineTextAlignment(.leading) .focused($focusedField, equals: index) } .onChange(of: focusedField) { newFocus in if newFocus == index { print("TextField \(index) is in focus") } else { print("TextField \(index) lost focus") } } .foregroundColor(.primary) } .buttonStyle(BorderlessButtonStyle()) .padding(.vertical, 4) } } #Preview { ContentView() .frame(width: 320, height: 250) }
2
0
344
Mar ’25