Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

Multi Platform App
Hi, Suppose I want to create an School management App that have little complex views so I need a three versions of each view one for Mac and one for iPadOS and one for iOS, cause using platform detector on same view and adjusting layout will make things messy. So what's the best way to achieve that ? Separate project to each platform ? maybe Targets which I still don't understand cause modifying a view in any target will be reflected to other targets so what's the best practice here ? Im working with SwiftUI Kind Regards
2
0
73
1d
Variable modification in forEach
Hi! I'm trying to do a forEach loop on an array of objects. Here's my code : ForEach($individus) { $individu in if individu.reussite == true { individu.score -= 10 } else { individu.score = (individu.levees * 10) + 20 + individu.score } } I have an error on the code in the 'if' saying that "Type '()' cannot conform to 'View'", but I have no idea on how solving this problem.
2
0
89
1d
Excessive ressource usage with NavigationLinks in LazyVStack
When a large number of NavigationLinks is within a LazyVStack (or LazyVGrid), ressource usage gets higher (and stays high) the further a user scrolls down. A simple example to reproduce this: NavigationStack { ScrollView { LazyVStack { ForEach(0..<5000) { number in NavigationLink(value: number) { Text("Number \(number)") } } } } .navigationDestination(for: Int.self) { number in Text("Details for number \(number)") } } List does not exhibit this behavior but is not suitable for my use case.
1
0
61
13h
SwiftUI TabView with .page Style: GeometryReader minX Not Updating on Page Scroll
I am working on a SwiftUI TabView with the .page style (indexDisplayMode: .never). I want to track the minX property of each tab's view using GeometryReader. However, I noticed inconsistent behavior when scrolling between pages. Here's the simplified code: import SwiftUI struct ContactScreenView: View { let text: String var body: some View { ZStack { Color.red.opacity(0.4).ignoresSafeArea() VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text(text) } .padding() } } } struct DemoView: View { @State private var selectedTab: Int = 0 var body: some View { VStack { TabView(selection: $selectedTab) { ContactScreenView(text: "followers") .background( GeometryReader(content: { geometry -> Color in let minX = geometry.frame(in: .global).minX print(minX) return Color.clear }) ) .tag(0) ContactScreenView(text: "following") .tag(1) ContactScreenView(text: "blocked") .tag(2) ContactScreenView(text: "Shared") .tag(3) } .tabViewStyle(.page(indexDisplayMode: .never)) } } } #Preview { DemoView() } Observed Behavior: When I scroll to the second page (index 1), the minX value updates correctly to screenWidth * 1, as expected. When I scroll to the third page (index 2), the minX value doesn't update at all. The ideal behavior would be for minX to update to screenWidth * 2 for the third page and so on, for subsequent pages. Expected Behavior: The minX value should correctly reflect the global position of each page as I scroll through the TabView. For example: Page 0: minX = 0 Page 1: minX = screenWidth * 1 Page 2: minX = screenWidth * 2 And so on.
1
0
36
10h
SwiftUI toolbar with IDs crash since macOS 15
I understand this is a known issue, but it’s truly unacceptable that it remains unresolved. Allowing users to customize toolbars is a fundamental macOS feature, and it has been broken since the release of macOS 15. How is it possible that this issue persists even in macOS 15.3 beta (24D5040f)? FB15513599 import SwiftUI struct ContentView: View { @State private var showEditItem = false var body: some View { VStack { VStack { Text("Instructions to reproduce the crash") .font(.title) .padding() Text(""" 1. Click on "Toggle Item" 2. In the menu go to File > New Window 3. In new window, click on "Toggle Item" """) } .padding() Button { showEditItem.toggle() } label: { Text("Toggle Item") } } .padding() .toolbar(id: "main") { ToolbarItem(id: "new") { Button { } label: { Text("New…") } } if showEditItem { ToolbarItem(id: "edit") { Button { } label: { Text("Edit…") } } } } } }
0
0
55
7h
SwiftUI - Drag gesture blocks scroll gesture only on iPhone 11
I'm pretty new to Swift and SwiftUI. I'm making my first app for sorting a gallery with some extra features. I was using my own iPhone for testing and just started testing my app on other Apple products. Everything works fine on iPad Air M1, iPhone 15 Pro, iPhone 15 Pro Max, iPhone 13, iPhone XS (Simulator), and iPhone 11 Pro (Simulator). However, when I tried to show my app to a family member with an iPhone 11, I came across an issue. Issue Description: My app takes all photos from iPhone's native gallery, then you can sort it by some spesific filters and delete pictures. It just looks like the native gallery. (I can add photos later if needed) You can just scroll the gallery by swiping up and down. You can press the select button and start selecting pictures to delete. I recently added a drag-to-select-multiple-pictures feature. This makes it feel more like the native iOS experience, eliminating the need to tap each picture individually. However, on the iPhone 11, the moment you open the app, you can't scroll. Scrolling is completely locked. You can still select pictures by tapping or dragging, so it's not a touch area issue. The same issue persists on the iPhone 11 simulator. And I think I found the problematic part in my (sadly messy) ContentView.swift file; ScrollView { RefreshControl(coordinateSpace: .named("refresh")) { await viewModel.refreshMediaItems() } LazyVGrid(columns: gridColumns, spacing: UIDevice.current.userInterfaceIdiom == .pad ? 12 : 4) { let items = viewModel.filteredItems(typeFilter: mediaTypeFilter, specialFilter: specialFilter) ForEach(Array(zip(items.indices, items)), id: \.1.id) { index, item in MediaThumbnailView( item: item, isSelected: selectedItems.contains(item.id), viewModel: viewModel, onLongPress: { if !isSelectionMode { toggleSelectionMode() selectedItems.insert(item.id) } }, onTap: { if isSelectionMode { toggleSelection(item: item) } else { viewModel.selectItem(item) } } ) .aspectRatio(1, contentMode: .fit) .background( GeometryReader { geometry in let frame = geometry.frame(in: .named("grid")) Color.clear.preference( key: ItemBoundsPreferenceKey.self, value: [ItemBounds(id: item.id, bounds: frame, index: index)] ) } ) } } .padding(.horizontal, 2) .coordinateSpace(name: "grid") .onPreferenceChange(ItemBoundsPreferenceKey.self) { bounds in itemBounds = Dictionary(uniqueKeysWithValues: bounds.map { ($0.id, $0) }) itemIndices = Dictionary(uniqueKeysWithValues: bounds.map { ($0.id, $0.index) }) } .gesture( DragGesture(minimumDistance: 0) .onChanged { gesture in if isSelectionMode { let location = gesture.location if !isDragging { startDragging(at: location, in: itemBounds) } updateSelection(at: location, in: itemBounds) } } .onEnded { _ in endDragging() } ) } .coordinateSpace(name: "refresh") } you can see the .gesture(.... part. I realised that this DragGesture and ScrollView blocks each other (somehow only on iPhone 11) highPriorityGesture also won't work. When I change it with simultaneousGesture, scroll starts to work again. BUT - since it's simultaneous, when multiple selection mode is activated, when I'm dragging my finger gallery also starts to scroll and it becomes a very unpleasant experience. After this issue I realised on native gallery iOS locks scroll when you are dragging for multiple selection and just when you release your finger you can scroll again even if the multiple selection mode is active. I tried a million things, asked claude, chatgpt etc. etc. Found some similar issues on stackoverflow but they were all related to iOS 18, not spesific to an iPhone. My app works fine on iOS 18 (15 Pro Max) iOS 18 drag gesture blocks scrollview Here are the some of the things I've tried: using highPriorityGesture and simultenousgesture together, tried to lock the scroll briefly while dragging, implement much complicated versions of these things with the help of claude, try to check if isSelectionMode is true or not All of them broke other things/won't work. Probably there's something pretty simple that I'm just missing; but iPhone 11 being the single problematic device confuses me. I don't want to mess too much with my already fragile logic.
0
0
34
15h
Find, clean, and free up space from large files! Slean lets you sort your gallery by size and efficiently manage your photos and videos with smart filtering and bulk delete options.
I'm pretty new to Swift and SwiftUI. I'm making my first app for sorting a gallery with some extra features. I was using my own iPhone for testing and just started testing my app on other Apple products. Everything works fine on iPad Air M1, iPhone 15 Pro, iPhone 15 Pro Max, iPhone 13, iPhone XS (Simulator), and iPhone 11 Pro (Simulator). However, when I tried to show my app to a family member with an iPhone 11, I came across an issue. Issue Description: My app takes all photos from iPhone's native gallery, then you can sort it by some spesific filters and delete pictures. It just looks like the native gallery. (I can add photos later if needed) You can just scroll the gallery by swiping up and down. You can press the select button and start selecting pictures to delete. I recently added a drag-to-select-multiple-pictures feature. This makes it feel more like the native iOS experience, eliminating the need to tap each picture individually. However, on the iPhone 11, the moment you open the app, you can't scroll. Scrolling is completely locked. You can still select pictures by tapping or dragging, so it's not a touch area issue. The same issue persists on the iPhone 11 simulator. And I think I found the problematic part in my (sadly messy) ContentView.swift file; ScrollView { RefreshControl(coordinateSpace: .named("refresh")) { await viewModel.refreshMediaItems() } LazyVGrid(columns: gridColumns, spacing: UIDevice.current.userInterfaceIdiom == .pad ? 12 : 4) { let items = viewModel.filteredItems(typeFilter: mediaTypeFilter, specialFilter: specialFilter) ForEach(Array(zip(items.indices, items)), id: \.1.id) { index, item in MediaThumbnailView( item: item, isSelected: selectedItems.contains(item.id), viewModel: viewModel, onLongPress: { if !isSelectionMode { toggleSelectionMode() selectedItems.insert(item.id) } }, onTap: { if isSelectionMode { toggleSelection(item: item) } else { viewModel.selectItem(item) } } ) .aspectRatio(1, contentMode: .fit) .background( GeometryReader { geometry in let frame = geometry.frame(in: .named("grid")) Color.clear.preference( key: ItemBoundsPreferenceKey.self, value: [ItemBounds(id: item.id, bounds: frame, index: index)] ) } ) } } .padding(.horizontal, 2) .coordinateSpace(name: "grid") .onPreferenceChange(ItemBoundsPreferenceKey.self) { bounds in itemBounds = Dictionary(uniqueKeysWithValues: bounds.map { ($0.id, $0) }) itemIndices = Dictionary(uniqueKeysWithValues: bounds.map { ($0.id, $0.index) }) } .gesture( DragGesture(minimumDistance: 0) .onChanged { gesture in if isSelectionMode { let location = gesture.location if !isDragging { startDragging(at: location, in: itemBounds) } updateSelection(at: location, in: itemBounds) } } .onEnded { _ in endDragging() } ) } .coordinateSpace(name: "refresh") } you can see the .gesture(.... part. I realised that this DragGesture and ScrollView blocks each other (somehow only on iPhone 11) highPriorityGesture also won't work. When I change it with simultaneousGesture, scroll starts to work again. BUT - since it's simultaneous, when multiple selection mode is activated, when I'm dragging my finger gallery also starts to scroll and it becomes a very unpleasant experience. After this issue I realised on native gallery iOS locks scroll when you are dragging for multiple selection and just when you release your finger you can scroll again even if the multiple selection mode is active. I tried a million things, asked claude, chatgpt etc. etc. Found some similar issues on stackoverflow but they were all related to iOS 18, not spesific to an iPhone. My app works fine on iOS 18 (15 Pro Max) iOS 18 drag gesture blocks scrollview Here are the some of the things I've tried: using highPriorityGesture and simultenousgesture together, tried to lock the scroll briefly while dragging, implement much complicated versions of these things with the help of claude, try to check if isSelectionMode is true or not All of them broke other things/won't work. Probably there's something pretty simple that I'm just missing; but iPhone 11 being the single problematic device confuses me. I don't want to mess too much with my already fragile logic.
0
0
35
15h
Implement two lists side by side with SwiftUI on iPad
I'm currently building an App using a TabView as the main navigation method. In my app I would like to build a page similar to the Top Charts in the native App Store App with two lists side by side: So far I came up with this code (simplified demo): import SwiftUI struct Demo: View { var body: some View { TabView { Tab("Main Tab", systemImage: "tray.and.arrow.down.fill") { NavigationStack { HStack { List { Text("Left List") } List { Text("Right List") } } .navigationTitle("Demo") .navigationBarTitleDisplayMode(.inline) } } } } } #Preview { Demo() } However, I’m encountering a couple of issues: • Scrolling to the top of the left list doesn’t trigger the toolbar background effect, and the content overlaps with the tabs in a strange way. Scrolling to the top of the right list works as expected. • The navigation title is always hidden. I haven’t been able to find a solution to these problems. What would be the correct approach? Thank you!
1
0
89
19h
looking for sample code 3d wireframe (with lines ) & polygons
Looking for sample code 3d wireframe (with lines ) & polygons and should be able to rotate (set camera angles) I tried sample code seems to be complicated & getting a BLANK screen import SwiftUI import SceneKit struct SceneKitTest2: View { var body: some View { VStack{ Text("SceneKitTest2") SceneView(scene: SCNScene(named:"Earth_1_12756.scn"), options: [.autoenablesDefaultLighting,.allowsCameraControl]) .frame(width:UIScreen.main.bounds.width, height: UIScreen.main.bounds.height/2) Spacer(minLength: 0) } } }
0
0
63
22h
Production app crashing with PlatformViewHost.updateNestedHosts(_:colorSchemeChanged:)
Hello, my production app is experiencing some crashes according to app store analytics. I cannot seem to reproduce it. According to Xcode Orginzer the app is crashing 10 SwiftUI 0x000000018ec372a0 PlatformViewHost.updateNestedHosts(_:colorSchemeChanged:) + 332 (PlatformViewHost.swift:699) Distributor ID: com.apple.AppStore Hardware Model: iPhone13,4 Version: 2.0.3 (86) AppStoreTools: 15E204 AppVariant: 1:iPhone13,4:16 Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd [1] OS Version: iPhone OS 17.4.1 (21E236) Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: SIGNAL 6 Abort trap: 6 Triggered by Thread: 0 Kernel Triage: VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter Thread 0 name: Thread 0 Crashed: 0 libsystem_kernel.dylib 0x00000001d1bd6974 __pthread_kill + 8 (:-1) 1 libsystem_pthread.dylib 0x00000001e56590ec pthread_kill + 268 (pthread.c:1717) 2 libsystem_c.dylib 0x0000000191627c14 __abort + 136 (abort.c:159) 3 libsystem_c.dylib 0x0000000191627b8c abort + 192 (abort.c:126) 4 libswiftCore.dylib 0x000000018832a690 swift::fatalErrorv(unsigned int, char const*, char*) + 136 (Errors.cpp:387) 5 libswiftCore.dylib 0x000000018832a6b0 swift::fatalError(unsigned int, char const*, ...) + 32 (Errors.cpp:395) 6 libswiftCore.dylib 0x0000000188324a08 getNonNullSrcObject(swift::OpaqueValue*, swift::TargetMetadata&lt;swift::InProcess&gt; const*, swift::TargetMetadata&lt;swift::InProcess&gt; const*) + 256 (DynamicCast.cpp:144) 7 libswiftCore.dylib 0x0000000188326510 tryCastToObjectiveCClass(swift::OpaqueValue*, swift::TargetMetadata&lt;swift::InProcess&gt; const*, swift::OpaqueValue*, swift::TargetMetadata&lt;swift::InProcess&gt; const*, swift::TargetMetadata&lt;swift::InPro... + 88 (DynamicCast.cpp:510) 8 libswiftCore.dylib 0x0000000188324068 tryCast(swift::OpaqueValue*, swift::TargetMetadata&lt;swift::InProcess&gt; const*, swift::OpaqueValue*, swift::TargetMetadata&lt;swift::InProcess&gt; const*, swift::TargetMetadata&lt;swift::InProcess&gt; const*&amp;, sw... + 992 (DynamicCast.cpp:2281) 9 libswiftCore.dylib 0x0000000188323b14 swift_dynamicCast + 208 (CompatibilityOverrideRuntime.def:109) 10 SwiftUI 0x000000018ec372a0 PlatformViewHost.updateNestedHosts(_:colorSchemeChanged:) + 332 (PlatformViewHost.swift:699) 11 SwiftUI 0x000000018ec36bf4 PlatformViewHost.updateEnvironment(_:viewPhase:) + 412 (PlatformViewHost.swift:690) 12 SwiftUI 0x000000018ec37bf8 PlatformViewHost.init(_:host:environment:viewPhase:importer:) + 808 (PlatformViewHost.swift:132) 13 SwiftUI 0x000000018ec36cf8 PlatformViewHost.__allocating_init(_:host:environment:viewPhase:importer:) + 92 (PlatformViewHost.swift:0) 14 SwiftUI 0x000000018ec0132c closure #1 in closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 444 (PlatformViewRepresentable.swift:559) 15 SwiftUI 0x000000018ec06c58 partial apply for closure #1 in closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 24 (&lt;compiler-generated&gt;:0) 16 SwiftUI 0x000000018ea26910 RepresentableContextValues.asCurrent&lt;A&gt;(do:) + 156 (RepresentableContextValues.swift:43) 17 SwiftUI 0x000000018ec01124 closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 176 (PlatformViewRepresentable.swift:558) 18 SwiftUI 0x000000018ec0104c closure #4 in closure #1 in PlatformViewChild.updateValue() + 128 (PlatformViewRepresentable.swift:557) 19 SwiftUI 0x000000018ec06b2c partial apply for closure #4 in closure #1 in PlatformViewChild.updateValue() + 24 (&lt;compiler-generated&gt;:0) 20 SwiftUI 0x000000018de7b7d0 closure #1 in _withObservation&lt;A&gt;(do:) + 44 (ObservationUtils.swift:26) 21 SwiftUI 0x000000018ec06b50 partial apply for closure #1 in _withObservation&lt;A&gt;(do:) + 24 (&lt;compiler-generated&gt;:0) 22 libswiftCore.dylib 0x0000000187fd0068 withUnsafeMutablePointer&lt;A, B&gt;(to:_:) + 28 (LifetimeManager.swift:82) 23 SwiftUI 0x000000018ebffbdc closure #1 in PlatformViewChild.updateValue() + 3040 (PlatformViewRepresentable.swift:556) 24 SwiftUI 0x000000018d5ecbf8 partial apply for implicit closure #1 in closure #1 in closure #1 in Attribute.init&lt;A&gt;(_:) + 32 (&lt;compiler-generated&gt;:0) 25 AttributeGraph 0x00000001b2150240 AG::Graph::UpdateStack::update() + 512 (ag-graph-update.cc:578) 26 AttributeGraph 0x00000001b2146f38 AG::Graph::update_attribute(AG::data::ptr&lt;AG::Node&gt;, unsigned int) + 424 (ag-graph-update.cc:719) 27 AttributeGraph 0x00000001b2146810 AG::Graph::input_value_ref_slow(AG::data::ptr&lt;AG::Node&gt;, AG::AttributeID, unsigned int, unsigned int, AGSwiftMetadata const*, unsigned char&amp;, long) + 720 (ag-graph.cc:1429)
3
4
544
May ’24
Crash when typing Japanese in TextEditor with TextSelection binding.
Environment Mac mini M4 Pro macOS: Version 15.1.1 (24B2091) Xcode: Version 16.1 (16B40) IME: Kotoeri, Google IME Code description struct ContentView: View { @State var text = “” @State var selection: TextSelection? var body: some View { VStack { TextEditor(text: $text, selection: $selection) } .padding() } } Issue Description When built for macOS (not Catalyst, Designed for iPad) and typing “あ” in Japanese input, it crashes. I tried using Kotoeri's Kana input, Kotoeri's Roman input, and Google IME, but the same error occurs and crashes in both cases. There is no issue when using English input. Errors (input method 56222 com.apple.inputmethod.Kotoeri.KanaTyping) (1): Fatal error: String index is out of bounds (input method 56338 com.apple.inputmethod.Kotoeri.RomajiTyping (1): Fatal error: String index is out of bounds Swift/StringUTF16View.swift:368: Fatal error: String index is out of bounds
1
0
134
1w
Multi Section Sidebar using List with selections for macOS
I'm trying to implement a 3 column NavigationSplitView in SwiftUI on macOS - very similar to Apple's own NavigationCookbook sample app - with the slight addition of multiple sections in the sidebar similar to how the Apple Music App has multiple sections in the sidebar. Note: This was easily possible using the deprecated NavigationLink(tag, selection, destination) API The most obvious approach is to simply do something like: NavigationSplitView(sidebar: { List { Section("Section1") { List(section1, selection: $selectedItem1) { item in NavigationLink(item.label, value: item) } } Section("Section2") { List(section2, selection: $selectedItem2) { item in NavigationLink(item.label, value: item) } } } }, content: { Text("Content View") }, detail: { Text("Detail View") }) But unfortunately, this doesn't work - it doesn't seem to properly iterate over all of the items in each List(data, selection: $selected) or the view is strangely cropped - it only shows 1 item. However if the 1 item is selected, then the appropriate bindable selection value is updated. See image below: If you instead use ForEach for enumerating the data, that does seem to work, however when you use ForEach, you loose the ability to track the selection offered by the List API, as there is no longer a bindable selection propery in the NavigationLink API. NavigationSplitView(sidebar: { List { Section("Section1") { ForEach(section1) { item in NavigationLink(item.label, value: item) } } Section("Section2") { ForEach(section2) { item in NavigationLink(item.label, value: item) } } } }, content: { Text("Content View") }, detail: { Text("Detail View") }) We no longer know when a sidebar selection has occurred. See image below: Obviously Apple is not going to comment on the expected lifespan of the now deprecated API - but I am having a hard time switching to the new NavigationLink with a broken sidebar implementation.
3
0
199
5d
SceneView with .frame() turns black
Hello, I experienced a strange behavior with SceneView and a .frame() modifier. Here is a minimal example: import SwiftUI import SceneKit struct MinimalSceneKitExample: View { var simpleScene: SCNScene { let scene = SCNScene() let boxGeometry = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0) let boxNode = SCNNode(geometry: boxGeometry) boxNode.position = SCNVector3(0, 0, 0) scene.rootNode.addChildNode(boxNode) return scene } var body: some View { SceneView( scene: SCNScene(), options: [.allowsCameraControl, .autoenablesDefaultLighting] ) .frame(maxWidth: .infinity, maxHeight: 312.6) } } This code turns the SceneView into a black view. Only some height values are causing this behavior. For example the height value 312.3 is fine. In my app, I'm using a dynamic height value that depends on the device's screen size which results in this behavior on some devices. Took me days to find this cause. So far integer values seem to always work which is what I will use as a quick fix for now. Should I file a bug ticket for this?
2
0
68
1d
Can't Widgetkit use lottie to implement the isOn state of toggle?
I introduced lottie to toggle in my widget to show a transition animation, but found that the.json file wouldn't load. The loading_hc.json file is validated and exists in the widget target. Ask for help, thank you! struct LottieView: UIViewRepresentable { let animationName: String func makeUIView(context: Context) -> LOTAnimationView { let lotAnimationView = LOTAnimationView(name: animationName, bundle: .main) lotAnimationView.contentMode = .scaleAspectFit lotAnimationView.play() return lotAnimationView } func updateUIView(_ uiView: LOTAnimationView, context: Context) { } func makeCoordinator() -> Coordinator { Coordinator() } } struct ControlToggleDisarmingStyle: ToggleStyle { func makeBody(configuration: Configuration) -> some View { if configuration.isOn { LottieView(animationName: "loading_hc.json").foregroundColor(.clear).frame(width: 24,height: 24) } else { Image("icon_disarm", bundle: Bundle.main).foregroundColor(.clear) } } }
2
0
121
2d
get location in app intent for interactive widgets
I have an app intent for interactive widgets. when I touch the toggle, the app intent perform to request location. func perform() async throws -> some IntentResult { var mark: LocationService.Placemark? do { mark = try await AsyncLocationServive.shared.requestLocation() print("[Widget] ConnectHandleIntent: \(mark)") } catch { WidgetHandler.shared.error = .locationUnauthorized print("[Widget] ConnectHandleIntent: \(WidgetHandler.shared.error!)") } return .result() } @available(iOSApplicationExtension 13.0, *) @available(iOS 13.0, *) final class AsyncLocationServive: NSObject, CLLocationManagerDelegate { static let shared = AsyncLocationServive() private let manager: CLLocationManager private let locationSubject: PassthroughSubject<Result<LocationService.Placemark, LocationService.Error>, Never> = .init() lazy var geocoder: CLGeocoder = { let geocoder = CLGeocoder() return geocoder }() @available(iOSApplicationExtension 14.0, *) @available(iOS 14.0, *) var isAuthorizedForWidgetUpdates: Bool { manager.isAuthorizedForWidgetUpdates } override init() { manager = CLLocationManager() super.init() manager.delegate = self } func requestLocation() async throws -> LocationService.Placemark { let result: Result<LocationService.Placemark, LocationService.Error> = try await withUnsafeThrowingContinuation { continuation in var cancellable: AnyCancellable? var didReceiveValue = false cancellable = locationSubject.sink( receiveCompletion: { _ in if !didReceiveValue { // subject completed without a value… continuation.resume(throwing: LocationService.Error.emptyLocations) } }, receiveValue: { value in // Make sure we only send a value once! guard !didReceiveValue else { return } didReceiveValue = true // Cancel current sink cancellable?.cancel() // We either got a location or an error continuation.resume(returning: value) } ) // Now that we monitor locationSubject, ask for the location DispatchQueue.global().async { self.manager.requestLocation() } } switch result { case .success(let location): // We got the location! return location case .failure(let failure): // We got an error :( throw failure } } // MARK: CLLocationManagerDelegate func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { defer { manager.stopUpdatingLocation() } guard let location = locations.first else { locationSubject.send(.failure(.emptyLocations)) return } debugPrint("[Location] location: \(location.coordinate)") manager.stopUpdatingLocation() if geocoder.isGeocoding { geocoder.cancelGeocode() } geocoder.reverseGeocodeLocation(location) { [weak self] marks, error in guard let mark = marks?.last else { self?.locationSubject.send(.failure(.emptyMarks)) return } debugPrint("[Location] mark: \(mark.description)") self?.locationSubject.send(.success(mark)) } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { locationSubject.send(.failure(.errorMsg(error.localizedDescription))) } } I found it had not any response when the app intent performed. And there is a location logo tips in the top left corner of phone screen.
2
0
114
6d
iPadOS 18 TabView with Large Navigation Title
I’m following the example code from Apple to implement the new iPadOS 18 TabView() with the new Tab(). While the tabbing itself is working fine, I can’t get it to show up a (large) navigation title in the sidebar (like the Home or Files app). I’ve tried placing .navigationTitle("App Name") at the TabView, but that doesn’t work. Is it possible to do this in any way or is this not recommended to show? TabView { Tab("Overview", systemImage: "film") { Text("Put a OverviewView here") } TabSection("Watch") { Tab("Movies", systemImage: "film") { Text("Put a MoviesView here") } Tab("TV Shows", systemImage: "tv") { Text("Put a TVShowsView here") } } TabSection("Listen") { Tab("Music", systemImage: "music.note.list") { Text("Put a MusicView here") } Tab("Podcasts", systemImage: "mic") { Text("Put a PodcastsView here") } } } .tabViewStyle(.sidebarAdaptable) .navigationTitle("App Name") .navigationBarTitleDisplayMode(.large) I know that there is also the .tabViewSidebarHeader() modifier, but that adds any view above the scroll view content. Neither does that easily allow to make it look like the regular navigation title, nor does it actually display in the navigation bar at the top, when scrolling down.
2
0
198
1w
iOS 18 Button with accented image is broken(cannot tap) in desktop widget.
In iOS 18 widget, button is broken when it's has an accented desaturated image as content, the button's AppIntent will not trigger perform function. checkout the code below: ` struct WidgetExtEntryView : View { var entry: Provider.Entry var body: some View { VStack { Text("count:") Text("\(WidgetExtAppIntent.count)") HStack { // button can not be tapped Button(intent: WidgetExtAppIntent(action: "+1")) { VStack { Image(systemName: "plus.square.fill").resizable() .widgetAccentedRenderingMode(.accentedDesaturated) // <-- here .frame(width: 50, height: 50) Text("Broken") } }.tint(.red) // button can be tapped Button(intent: WidgetExtAppIntent(action: "+1")) { VStack { Image(systemName: "plus.square.fill").resizable() .widgetAccentedRenderingMode(.fullColor) // <-- here .frame(width: 50, height: 50) Text("OK").frame(width: 50, alignment: .center) } }.tint(.green) } .minimumScaleFactor(0.5) } } } ` check out the full demo project: ButtonInWidgetBrokenIOS18
2
0
173
Dec ’24
NavigationSplitView detail view not updating
I have a NavigationSplitView with all three columns, and NavigationLinks in the sidebar to present different Lists for the content column. When a list item is selected in the content view, I want to present a view in the detail view. Since different detail views should be presented for different content views, I represent state like this (some details omitted for space): // Which detail view to show in the third column enum DetailViewKind: Equatable { case blank case localEnv(RegistryEntry) case package(SearchResult) } // Which link in the sidebar was tapped enum SidebarMenuItem: Int, Hashable, CaseIterable { case home case localEnvs case remoteEnvs case packageSearch } // Binds to a DetailViewKind, defines the activate SidebarMenuItem struct SidebarView: View { @State private var selectedMenuItem: SidebarMenuItem? @Binding var selectedDetailView: DetailViewKind var body: some View { VStack(alignment: .leading, spacing: 32) { SidebarHeaderView() Divider() // Creates the navigationLinks with a SidebarMenuRowView as labels SidebarMenuView(selectedMenuItem: $selectedMenuItem, selectedDetailView: $selectedDetailView) Spacer() Divider() SidebarFooterView() } .padding() .frame(alignment: .leading) } } struct SidebarMenuRowView: View { var menuItem: SidebarMenuItem @Binding var selectedMenuItem: SidebarMenuItem? @Binding var selectedDetailView: DetailViewKind private var isSelected: Bool { return menuItem == selectedMenuItem } var body: some View { HStack { Image(systemName: menuItem.systemImageName).imageScale(.small) Text(menuItem.title) Spacer() } .padding(.leading) .frame(height: 24) .foregroundStyle(isSelected ? Color.primaryAccent : Color.primary) .background(isSelected ? Color.menuSelection : Color.clear) .clipShape(RoundedRectangle(cornerRadius: 10)) .navigationDestination(for: SidebarMenuItem.self) { item in navigationDestinationFor(menuItem: item, detailView: $selectedDetailView) } .onTapGesture { if menuItem != selectedMenuItem { selectedMenuItem = menuItem } } } } // Determines which detail view to present struct DetailView: View { @Binding var selectedDetailView: DetailViewKind var innerView: some View { switch selectedDetailView { case .blank: AnyView(Text("Make a selection") .font(.subheadline) .foregroundStyle(.secondary) .navigationSplitViewColumnWidth(min: 200, ideal: 350)) case .localEnv(let regEntry): AnyView(EnvironmentDetailView(regEntry: regEntry)) case .package(let searchResult): AnyView(PackageDetailView(searchResult: searchResult)) } } var body: some View { innerView } } struct ContentView: View { @State private var detailView: DetailViewKind = .blank var body: some View { NavigationSplitView { SidebarView(selectedDetailView: $detailView) .navigationSplitViewColumnWidth(175) } content: { HomeView() .navigationSplitViewColumnWidth(min: 300, ideal: 450) } detail: { DetailView(selectedDetailView: $detailView) } } } My issue is that the detail view is not updated when the ContentView's detailView property is updated. I've verified that the value itself is changing, but the view is not. I searched around to see why this would be (this is my first Swift/SwiftUI application) and from what I gather a @Binding alone will not cause a view to be updated, that binding either needs to be used in the view hierarchy, or it needs to be stored as a @State property that gets updated when the binding value changes. I added a dummy @State property to DetailView and that still doesn't work, so I'm a little confused: struct DetailView: View { @Binding var selectedDetailView: DetailViewKind @State private var dummyProp: DetailViewKind? var innerView: some View { switch selectedDetailView { case .blank: AnyView(Text("Make a selection") .font(.subheadline) .foregroundStyle(.secondary) .navigationSplitViewColumnWidth(min: 200, ideal: 350)) case .localEnv(let regEntry): AnyView(EnvironmentDetailView(regEntry: regEntry)) case .package(let searchResult): AnyView(PackageDetailView(searchResult: searchResult)) } } var body: some View { innerView.onChange(of: selectedDetailView) { dummyProp = selectedDetailView } } } Any ideas?
0
0
107
2d