Post

Replies

Boosts

Views

Activity

Reply to How to unit test that a radio button is setting state var correctly in swiftui
This is my first time replying to a forum post, so bear with me haha. If you want to unit test views, you need to hold all their data in viewModels (which is the recommended architecture, so you should always do that anyways). So create a viewmodel for your view that would hold the gameType variable and then create a function that would either set it to 1 or 2 (if you only need 2 options for your radio buttons, just hold the info in a bool | if you need more options, use an enum, that way you leave no space for weird errors when you mistype an Int). So here's your viewModel: class YourViewModel: ObservableObject { @Published var gameType: Int = 1 func changeGameType(to number: Int) { DispatchQueue.main.async { // Important! View updates should only be made from main thread self.gameType = number } } } } Your view: struct YourView: View { @ObservedObject private var viewModel = YourViewModel() var body: some View { YourButtonView(title: "Change Game Type to 2", selectedGameType: $viewModel.gameType) { viewModel.changeGameType(to: 2) } } } Your button view: (not a radio button obvs, adapt to needs) struct YourButtonView: View { let title: String let action: () -> Void @Binding var selectedGameType: Int init(title: String, selectedGameType: Binding<Int>, action: @escaping () -> Void) { self.title = title self._selectedGameType = selectedGameType self.action = action } var body: some View { Button(title, action: action) } } And the unit test: func testGameType() { // Note: Since we used DispatchQueue.main.async in our function testing the function as if it was a synchronous one will fail! // So we will use Combine instead // Given let viewModel = YourViewModel() let expectation = XCTestExpectation(description: "Changes game type to 2.") var cancellable: AnyCancellable? cancellable = viewModel.$gameType .dropFirst() // We remove the inital value (in our case 1) .sink { gameType in // Assert new gameType value XCTAssert( gameType == 2, "Value expected to be 2, but got \(gameType) instead" ) // Fulfill expectation expectation.fulfill() } // When ( We imitate the radio button press by calling its function ) viewModel.changeGameType(to: 2) // Then wait(for: [expectation], timeout: 1) }
Oct ’23
Reply to Convert a PhotosPickerItem to an Image in SwiftUI on MacOS
UI Elements (as in UIImage) are from UIKit which is the framework for iOS. Its equivalent for macOS is AppKit which uses NS Elements (as in NSImage). Lots of times they work in extremely similar ways. So you can use NSImage same way you would UIImage -> just do NSImage(data: data) to initalize an NSImage and then use it in SwiftUI with Image(nsImage: NSImage). If you're super used to typing out UIImage every time you could even do a typealias like this: typealias UIImage = NSImage to keep using the term UIImage in your macOS application.
Oct ’23
Reply to Sheet will change to dark theme from toggle but won't change back to light mode
I've never figured out how to make forced color themes work in pure SwiftUI but this is what I did for one of my apps that worked fine for me. ( I didn't try it specifically from a sheet but I'd be very confused if it didn't work Note: This is for the whole app, not only for one view. // Create an enum case for every theme enum ColorTheme: String, CaseIterable { case light case dark case system } @main struct ExampleApp: App { // Save user's choice in preferences (userdefaults) @AppStorage("colorTheme") private var colorTheme: ColorTheme = .system var body: some Scene { WindowGroup { SplashScreen() .onAppear { overrideColorTheme() } .onChange(of: colorTheme) { _ in overrideColorTheme() } } } func overrideColorTheme() { var userInterfaceStyle: UIUserInterfaceStyle switch colorTheme { case .light: userInterfaceStyle = .light case .dark: userInterfaceStyle = .dark case .system: userInterfaceStyle = .unspecified } UIApplication.shared.windows.first?.overrideUserInterfaceStyle = userInterfaceStyle } } Now from anywhere in your app you can update the value stored in UserDefaults and it will update the color theme used in your whole app. Like so: struct ExampleView: View { @AppStorage("colorTheme") private var colorTheme: ColorTheme = .system var body: some View { VStack { Button("Set to Light") { colorTheme = .light } Button("Set to Dark") { colorTheme = .dark } Button("Set to System") { colorTheme = .system } } } } Just checked and saw that since iOS 15.0 UIApplication.shared.windows is deprecated so you could use an extension like this for 15 and above extension UIApplication { func setColorTheme(to theme: UIUserInterfaceStyle) { let keyWindow = self.connectedScenes // Keep only active scenes, onscreen and visible to the user .filter { $0.activationState == .foregroundActive } // Keep only the first `UIWindowScene` .first(where: { $0 is UIWindowScene }) // Get its associated windows .flatMap({ $0 as? UIWindowScene })?.windows // Finally, keep only the key window .first(where: \.isKeyWindow) keyWindow?.overrideUserInterfaceStyle = theme } } And use it like so in the previous mentioned overrideColorTheme() function: UIApplication.shared.setColorTheme(to: userInterfaceStyle)
Oct ’23
Reply to Combine views in SwiftUI
From my understanding of your question I think what you're looking for is ScrollView. Just wrap all the views in a ScrollView and you'll get one coherent, scrollable view. Like so: @AppStorage("MediAnsicht") var MedisEinfacheAnsicht = false var body: some View { if MedisEinfacheAnsicht == true { ScrollView { AcetylsalicylsaeureAllgInfos() AcetylsalicylsaeureKontraind() AcetylsalicylsaeureUAWs() } } else { AcetylsalicylsaeureMenu() } } }
Nov ’23