using swiftUI i have a lot of Buttons which i need to make only one can be clicked at the same time.
By default in swiftUI you have two or more buttons on a view you can click them all at once
I tried adding the following:
UIButton.appearance().isMultipleTouchEnabled = false
UIButton.appearance().isExclusiveTouch = true
With UIKit we had exclusiveTouch and MultiTouchEnabled but how do we do this with swiftUI?
What is the correct way to solve this application wide?
Update: The use case is simple there is a view with a login button and a register button and now the user can tap both at the same time which i don't want
I have a SwiftUI view which was originally only used for an iOS widget. I would like to re-use this view now for a watchOS app.
#Environment(.widgetFamily) var widgetFamily
The widgetFamily surprisingly was set to ".accessoryCircular". Is this some kind of strange default? This happens within the context of the main watchOS app - no widgets and no complications involved at this stage.
I would like to distinguish between the "accessoryCircular" iOS widget and the main watchOS app. How can I achieve this?
TL;DR: Is there any way to have custom button style (custom pressed state) in SwiftUI on tvOS while it is still working correctly with Accessibility Focus API and therefore its hasFocus works in UI tests?
Please visit dedicated Github repo for a longer version and a sample project with UI tests example.
What is the problem?
To create a custom button in SwiftUI on tvOS and can customize it based on pressed state, you can implement custom ButtonStyle.
Button(...)
.buttonStyle(AnyCustomButtonStyle())
and then use ButtonConfiguration.isPressed in the view.
However, I have found that although the button visually looks focused, it does not really report as Focused in Accessibility API. See the sample project for example and actual test showing the problem.
Among other problems, it makes the button quite difficult to work with in tvOS UI tests. tvOS is relying on focus for navigation and because the button's hasFocus always stays false (even if the button renders in focused appearance), it can prevent a lot of useful APIs to work in tests.
Why do you need custom ButtonStyle on tvOS?
I know Apple provides some custom PrimitiveButtonStyle implementations (like CardButtonStyle), but those don't provide enough flexibility. They all modify your button (e.g. add background).
Not being able to use custom buttonStyle makes it impossible to implement for example Capsule-style buttons like this...
First button focused
First button focused and pressed
Please let's leave aside the discussion if it is a good idea or not 😃 ... Just trying to find if there is a solution or if it is eventually a bug of SwiftUI.
What is the issue with Accessibility?
Without custom button, the button reports as Focused to Accessibility in UI tests.
Without custom style
(lldb) po app
Attributes: Application, 0x12ed10b30, pid: 61273, label: 'FocusSwiftUI'
Element subtree:
→Application, 0x12ed10b30, pid: 61273, label: 'FocusSwiftUI'
...
Button, 0x12ed0c660, {{468.0, 477.0}, {298.0, 126.0}}, label: 'Button 1'
Button, 0x12ed0c770, {{453.0, 470.7}, {328.0, 138.7}}, Focused
Button, 0x12ed0c1e0, {{806.0, 477.0}, {303.0, 126.0}}, label: 'Button 2'
Button, 0x12ed0c2f0, {{791.0, 470.8}, {333.0, 138.5}}
...
However, the moment you set buttonStyle to any custom one, the output changes drastically...
(lldb) po app
Attributes: Application, 0x106d0cd40, pid: 70156, label: 'FocusSwiftUI'
Element subtree:
→Application, 0x106d0cd40, pid: 70156, label: 'FocusSwiftUI'
...
Button, 0x106d0ce50, {{707.0, 505.0}, {142.0, 71.0}}, label: 'Button 1'
Button, 0x106d0cf60, {{885.0, 505.0}, {146.0, 71.0}}, label: 'Button 2'
Button, 0x106d0d180, {{1067.0, 505.0}, {147.0, 71.0}}, label: 'Button 3'
...
Notice there is no more Focused button anywhere... We will never get any button with hasFocus == true in queries for example...
What else did I try?
I tried to experiment with many (probably all) .accessibility... modifiers before asking.
Many different results, but none of them ever had proper focus behavior in UI tests...
.accessibilityChildren: close to default button behavior in terms of accessibility structure (e.g. nested buttons)
.accessibilityRepresentation: button never gets visually highlighted
Temporary workaround
For now there seems to be no solution in sight. I have implemented rather complicated hack to get at least UI tests working for now.
In a nutshell: When the app is running in a context of UI tests (determined through Launch Arg), each affected button adds clear color background (it has no visual or behavioral impact) when focused. The background color then has a constant accessibilityIdentifier (e.g. "MY_FOCUSED", I call it "custom focus marker"). When evaluating if element is focused in UI tests, I then check if the button contains child element where accessibilityIdentifier == "MY_FOCUSED".
It is nasty, but somehow good enough for UI tests and actually works reliably so far. It works thanks to the fact there is always only one focused item at the same time and the "if focused -> set background" takes care of the automatic update of the "custom focus marker".
You can try to set accessibilityRepresentstion - does it help?
Button(..)
.buttonStyle(AnyCustomButtonStyle())
.accessibilityRepresentation {
Button(..)
}
Edit:
Another idea - what about having the “correct” Button in the background of your custom? Something like:
Button(..)
.buttonStyle(AnyCustomButtonStyle())
.background(
Button(..).opacity(0.0001) //it may work even with opacity 0
)
You may additionally improve it with making the visible button hidden to accessibility with .accessibility(hidden: true)
If you're looking for actual VoiceOver accessibility (not using it as a UI test tool I mean) you can use the isFocused environment variable and on change, call UIAccessibility.post(notification: .announcement, argument: "Your message")
I'm using a TabView inside NavigationView but my app crashes when I try to navigate backwards, it shows this error message "Thread 1: EXC_BAD_ACCESS (code=2, address=0x16ad5bff0)" at AppDelegate class. In ios 14 device it works fine but it crashes on ios 13. I think this is navigationView issue in ios 13. I'm looking for an alternative in iOS 13 and avoid the crash.
PS: I'm using xcode 12.
Nesting TabView's inside of NavigationView's has been an issue since SwiftUI started. The cleanest workaround to this is to create view "View layers". Take a look this answer to give you an idea about how they work.
Pure SwiftUI login, signup, register flow, is it possible?
There is a lot that you can do with layering in SwiftUI that feels natural. Check it out and let me know if you have any questions!
I'm working on rewriting an app to SwiftUI. Currently I'm struggling with what seems an easy one: Disabling the translucence in NavigationView.
The code I used before is:
UINavigationBar.appearance().isTranslucent = false
But isTranslucent is not in the autocomplete suggestions.
If I put it anyway, the app crashes inside the ViewRendererHost.render(interval:updateDisplayList:) :
Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1c34016a0)
Did I miss something? How can I disable the translucence of NavigationView in SwiftUI?
Thank you for your suggestions!
This is a bug, and you will instead have to continue using UINavigationController. You can still have all your content as SwiftUI in UIHostingControllers, but you will have to keep the UIKit navigation stack or it'll explode.