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

Posts under SwiftUI tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Issue with observing SwiftData model and UndoManager
I have created a minimum example to demonstrate an issue with observing SwiftData model and UndoManager. This project includes a simple NavigationSplitView, an Item SwiftData model that is being persisted and an enabled UndoManager. Problem: The SwiftData model Item can be observed as expected. Changing the date in the DetailView works as expected and all related views (ListElementView + DetailView) are updated as expected. When pressing ⌘+Z to undo with the enabled UndoManager, deletions or inserts in the sidebar are visible immediately (and properly observed by ContentView). However, when changing the timestamp and pressing ⌘+Z to undo that change, it is not properly observed and immediately updated in the related views (ListElementView + DetailView). Further comments: Undo operation to the model value changes (here: timestamp) are visible in the DetailView when changing sidebar selections Undo operation to the model value changes (here: timestamp) are visible in the ListElementView when restarting the app Undo operation to the model value changes (here: timestamp) are are properly observed and immediately visible in the sidebar, when ommiting the ListElementView (no view encapsulation) Relevant code base: struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var items: [Item] @State private var selectedItems: Set<Item> = [] var body: some View { NavigationSplitView { List(selection: $selectedItems) { ForEach(items) { item in ListElementView(item: item) .tag(item) } .onDelete(perform: deleteItems) } .navigationSplitViewColumnWidth(min: 180, ideal: 200) .toolbar { ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } detail: { if let item = selectedItems.first { DetailView(item: item) } else { Text("Select an item") } } .onDeleteCommand { deleteSelectedItems() } } private func addItem() { withAnimation { let newItem = Item(timestamp: Date()) modelContext.insert(newItem) } } private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(items[index]) } } } private func deleteSelectedItems() { for selectedItem in selectedItems { modelContext.delete(selectedItem) selectedItems.remove(selectedItem) } } } struct ListElementView: View { @Bindable var item: Item var body: some View { Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))") } } struct DetailView: View { @Bindable var item: Item var body: some View { Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) DatePicker(selection: $item.timestamp, label: { Text("Change Date:") }) } } @Model final class Item { var timestamp: Date init(timestamp: Date) { self.timestamp = timestamp } } It seems that the UndoManager does not trigger a redraw of the ContentView through the items query? Is this a bug or a feature?
0
0
137
2w
SwiftUI List OutlineGroup
Hello, I'm having some difficulties trying to customise a SwiftUI list-detail splitview using List and OutlineGroup: The model used is provided in Apple documentation OutlineGroup. The contentView is struct ContentView: View { @State var itemString = String() var body: some View { HSplitView { MyOutLine(title: "MyOutLine", itemString: $itemString) .frame(width: 200, height: 300 , alignment: Alignment(horizontal: .leading, vertical: .top)) .padding() MyView(itemString: itemString) } } } The left view is struct MyOutLine: View { let title:String @Binding var itemString:String @State private var selection: FileItem? var body: some View { List(selection: $selection) { OutlineGroup(data, children: \.children) { item in Text ("\(item.description)") .onTapGesture { selection = item itemString = item.description } .listRowBackground( selection == item ? Color.gray :nil ) } } .listStyle(.sidebar) .onAppear { itemString = "No selection"} } } The right view is: struct MyView: View { let itemString:String var body: some View { VStack{ Spacer() HStack { Spacer() Text(itemString) Spacer() } Spacer() } } } The result works but I have 2 problems: The selection works but the detail view is updated only when I click the text but not when I click the rest of the row. This results in the detail view not being sync with the list selection. I would like to customise the colour of the selected row but listRowBackground does not seem to work. Is there a way to fix this Thank you in advance Jean Marie
2
0
238
2w
iOS 18 Translation API availability for UIKit
After reading the documentation for TranslationSession and other API methods I got an impression that it will not be possible to use the Translation API with UI elements built with UIKit. You don’t instantiate this class directly. Instead, you obtain an instance of it by adding a translationTask(_:action:) or translationTask(source:target:action:) function to the SwiftUI view containing the content you want to translate So the main question I have to the engineers of mentioned framework is will there be any support for UIKit or app developers will have to rewrite their apps in SwiftUI just to be able to use the Translation API?
1
1
427
2w
SwiftUI State not reliable updating
Hello, I have a SwiftUI view with the following state variable: @State private var startDate: Date = Date() @State private var endDate: Date = Date() @State private var client: Client? = nil @State private var project: Project? = nil @State private var service: Service? = nil @State private var billable: Bool = false Client, Project, and Service are all SwiftData models. I have some view content that binds to these values, including Pickers for the client/project/service and a DatePicker for the Dates. I have an onAppear listener: .onAppear { switch state.mode { case .editing(let tt): Task { await MainActor.run { startDate = tt.startDate endDate = tt.endDate client = tt.client project = tt.project service = tt.service billable = tt.billable } } default: return } } This works as expected. However, if I remove the Task & MainActor.run, the values do not fully update. The DatePickers show the current date, the Pickers show a new value but tapping on them shows a nil default value. What is also extremely strange is that if tt.billable is true, then the view does update as expected. I am using Xcode 15.4 on iOS simulator 17.5. Any help would be appreciated.
0
0
188
3w
SwiftUI keyboard shortcuts don't become active until view loads
I have a menu bar extra app that includes a sub-menu for lesser used functions. The sub menu implements .keyboardShortcut for a few of the menu items. When the app is first the active app, the keyboard shortcuts only produce a beep UNTIL the sub menu has been accessed. Once the sub-menu has loaded, the keyboard shortcuts work as expected. I should note that the MenuBarExtra is using the .window display mode, if that's important. The submenu appears with a button press within the MenuBarExtra. Is there a method to expose the keyboard shortcuts to the system before the view has loaded?
1
0
129
3w
Tokenised text search in SwiftData help
The SwiftData predicate documentation says that it supports the contains(where:) sequence operation in addition to the contains(_:) string comparison but when I put them together in a predicate to try and perform a tokenised search I get a runtime error. Unsupported subquery collection expression type (NSInvalidArgumentException) I need to be able to search for items that contain at least one of the search tokens, this functionality is critical to my app. Any suggestions are appreciated. Also does anyone with experience with CoreData know if this is possible to do in CoreData with NSPredicate? import SwiftData @Model final class Item { var textString: String = "" init() {} } func search(tokens: Set<String>, context: ModelContext) throws -> [Item] { let predicate: Predicate<Item> = #Predicate { item in tokens.contains { token in item.textString.contains(token) } } let descriptor = FetchDescriptor(predicate: predicate) return try context.fetch(descriptor) }
2
1
323
3w
Is it possible to get a swiftUI timer-text to align .trailing?
Please consider simple example below. I am trying to put a timer in the upper right corner of a live activity. I am done, it works, but I'm trying to get the timer to look better. If I take a regular text, I can get it to align properly by adjusting the .frame(), , but for a text with a timer inside it, alignment is ignored from what I can see. Text("Hello").frame(width: 90, alignment: .trailing).border(.red) /*Text(timerInterval: timeRange, countsDown: false) .monospacedDigit().font(.subheadline).frame(width: 90, alignment: .trailing).border(.red)*/ } Is there any way to fix this? Right now, I have a fixed width so that HH:mm:ss will fit, but that doesn't look super great if it's just minutes and seconds for example, there's an empty block to the right
1
0
170
3w
Voice recorder app recording in dual mono instead of stereo
Hi y'all, After getting mono recording working, I want to differentiate my app from the standard voice memos to allow for stereo recording. I followed this tutorial (https://developer.apple.com/documentation/avfaudio/capturing_stereo_audio_from_built-in_microphones) to get my voice recorder to record stereo audio. However, when I look at the waveform in Audacity, both channels are the same. If I look at the file info after sharing it, it says the file is in stereo. I don't exactly know what's going on here. What I suspect is happening is that the recorder is only using one microphone. Here is the relevant part of my recorder: // MARK: - Initialization override init() { super.init() do { try configureAudioSession() try enableBuiltInMicrophone() try setupAudioRecorder() } catch { // If any errors occur during initialization, // terminate the app with a fatalError. fatalError("Error: \(error)") } } // MARK: - Audio Session and Recorder Configuration private func enableBuiltInMicrophone() throws { let audioSession = AVAudioSession.sharedInstance() let availableInputs = audioSession.availableInputs guard let builtInMicInput = availableInputs?.first(where: { $0.portType == .builtInMic }) else { throw Errors.NoBuiltInMic } do { try audioSession.setPreferredInput(builtInMicInput) } catch { throw Errors.UnableToSetBuiltInMicrophone } } private func configureAudioSession() throws { let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setCategory(.record, mode: .default, options: [.allowBluetooth]) try audioSession.setActive(true) } catch { throw Errors.FailedToInitSessionError } } private func setupAudioRecorder() throws { let date = Date() let dateFormatter = DateFormatter() dateFormatter.locale = Locale(identifier: "en_US_POSIX") dateFormatter.dateFormat = "yyyy-MM-dd, HH:mm:ss" let timestamp = dateFormatter.string(from: date) self.recording = Recording(name: timestamp) guard let fileURL = recording?.returnURL() else { fatalError("Failed to create file URL") } self.currentURL = fileURL print("Recording URL: \(fileURL)") do { let audioSettings: [String: Any] = [ AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVLinearPCMIsNonInterleaved: false, AVSampleRateKey: 44_100.0, AVNumberOfChannelsKey: isStereoSupported ? 2 : 1, AVLinearPCMBitDepthKey: 16, AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue ] audioRecorder = try AVAudioRecorder(url: fileURL, settings: audioSettings) } catch { throw Errors.UnableToCreateAudioRecorder } audioRecorder.delegate = self audioRecorder.prepareToRecord() } //MARK: update orientation public func updateOrientation(withDataSourceOrientation orientation: AVAudioSession.Orientation = .front, interfaceOrientation: UIInterfaceOrientation) async throws { let session = AVAudioSession.sharedInstance() guard let preferredInput = session.preferredInput, let dataSources = preferredInput.dataSources, let newDataSource = dataSources.first(where: { $0.orientation == orientation }), let supportedPolarPatterns = newDataSource.supportedPolarPatterns else { return } isStereoSupported = supportedPolarPatterns.contains(.stereo) if isStereoSupported { try newDataSource.setPreferredPolarPattern(.stereo) } try preferredInput.setPreferredDataSource(newDataSource) try session.setPreferredInputOrientation(interfaceOrientation.inputOrientation) } Here is the relevant part of my SwiftUI view: RecordView() .onAppear {             Task {                 if await AVAudioApplication.requestRecordPermission() {                     // The user grants access. Present recording interface.                     print("Permission granted")                 } else {                     // The user denies access. Present a message that indicates                     // that they can change their permission settings in the                     // Privacy & Security section of the Settings app.                     model.showAlert.toggle()                 }                 try await recorder.updateOrientation(interfaceOrientation: deviceOrientation)             }         }         .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in                     if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,                        let orientation = windowScene.windows.first?.windowScene?.interfaceOrientation {                         deviceOrientation = orientation                         Task {                             do {                                 try await recorder.updateOrientation(interfaceOrientation: deviceOrientation)                             } catch {                                 throw Errors.UnableToUpdateOrientation                             }                         }                     }                 } Here is the full repo: https://github.com/aabagdi/MemoMan/tree/MemoManStereo Thanks for any leads!
1
0
235
3w
Crash After Presenting SwiftUI Alert
I’m seeing a crash in production for a small percentage of users, and have narrowed it down based on logging to happening as or very shortly after an alert is presented using SwiftUI. This seems to be isolated to iOS 17.5.1, but since it’s a low-volume crash I can’t be sure there aren’t other affected versions. What can I understand from the crash report? Here’s a simplified version of the code which presents the alert, which seems so simple I can’t understand why it would crash. And following that is the crash trace. // View (simplified) @MainActor public struct MyView: View { @ObservedObject var model: MyViewModel public init(model: MyViewModel) { self.model = model } public var body: some View { myViewContent .overlay(clearAlert) } var clearAlert: some View { EmptyView().alert( "Are You Sure?", isPresented: $model.isClearAlertVisible, actions: { Button("Keep", role: .cancel) { model.clearAlertKeepButtonWasPressed() } Button("Delete", role: .destructive) { model.clearAlertDeleteButtonWasPressed() } }, message: { Text("This cannot be undone.") } ) } } // Model (simplified) @MainActor public final class MyViewModel: ObservableObject { @Published var isClearAlertVisible = false func clearButtonWasPressed() { isClearAlertVisible = true } func clearAlertKeepButtonWasPressed() { // No-op. } func clearAlertDeleteButtonWasPressed() { // Calls other code. } } Incident Identifier: 36D05FF3-C64E-4327-8589-D8951C8BAFC4 Distributor ID: com.apple.AppStore Hardware Model: iPhone13,2 Process: My App [379] Path: /private/var/containers/Bundle/Application/B589E780-96B2-4A5F-8FCD-8B34F2024595/My App.app/My App Identifier: com.me.MyApp Version: 1.0 (1) AppStoreTools: 15F31e AppVariant: 1:iPhone13,2:15 Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd [1] Coalition: com.me.MyApp [583] Date/Time: 2024-06-21 20:09:20.9767 -0500 Launch Time: 2024-06-20 18:41:01.7542 -0500 OS Version: iPhone OS 17.5.1 (21F90) Release Type: User Baseband Version: 4.50.06 Report Version: 104 Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001a69998c0 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [379] 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 libswiftCore.dylib 0x00000001a69998c0 _assertionFailure(_:_:file:line:flags:) + 264 (AssertCommon.swift:144) 1 AttributeGraph 0x00000001d0cd61a4 Attribute.init<A>(body:value:flags:update:) + 352 (Attribute.swift:473) 2 SwiftUI 0x00000001ac034054 closure #1 in Attribute.init<A>(_:) + 128 (<compiler-generated>:0) 3 SwiftUI 0x00000001ac033cac partial apply for closure #1 in Attribute.init<A>(_:) + 32 (<compiler-generated>:0) 4 libswiftCore.dylib 0x00000001a6ad0450 withUnsafePointer<A, B>(to:_:) + 28 (LifetimeManager.swift:128) 5 SwiftUI 0x00000001ad624d14 closure #2 in UIKitDialogBridge.startTrackingUpdates(actions:) + 268 (UIKitDialogBridge.swift:370) 6 SwiftUI 0x00000001ad624ae0 UIKitDialogBridge.startTrackingUpdates(actions:) + 248 (UIKitDialogBridge.swift:369) 7 SwiftUI 0x00000001ad6250cc closure #4 in UIKitDialogBridge.showNewAlert(_:id:) + 72 (UIKitDialogBridge.swift:471) 8 SwiftUI 0x00000001abfdd050 thunk for @escaping @callee_guaranteed () -> () + 36 (:-1) 9 UIKitCore 0x00000001aa5722e4 -[UIPresentationController transitionDidFinish:] + 1096 (UIPresentationController.m:651) 10 UIKitCore 0x00000001aa571d88 __56-[UIPresentationController runTransitionForCurrentState]_block_invoke.114 + 320 (UIPresentationController.m:1390) 11 UIKitCore 0x00000001aa5cb9ac -[_UIViewControllerTransitionContext completeTransition:] + 116 (UIViewControllerTransitioning.m:304) 12 UIKitCore 0x00000001aa34a91c __UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK__ + 36 (UIView.m:16396) 13 UIKitCore 0x00000001aa34a800 -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 624 (UIView.m:16429) 14 UIKitCore 0x00000001aa349518 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 436 (UIView.m:0) 15 UIKitCore 0x00000001aa356b14 -[UIViewAnimationState animationDidStop:finished:] + 192 (UIView.m:2400) 16 UIKitCore 0x00000001aa356b84 -[UIViewAnimationState animationDidStop:finished:] + 304 (UIView.m:2422) 17 QuartzCore 0x00000001a96f8c50 run_animation_callbacks(void*) + 132 (CALayer.mm:7714) 18 libdispatch.dylib 0x00000001aff61dd4 _dispatch_client_callout + 20 (object.m:576) 19 libdispatch.dylib 0x00000001aff705a4 _dispatch_main_queue_drain + 988 (queue.c:7898) 20 libdispatch.dylib 0x00000001aff701b8 _dispatch_main_queue_callback_4CF + 44 (queue.c:8058) 21 CoreFoundation 0x00000001a808f710 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 (CFRunLoop.c:1780) 22 CoreFoundation 0x00000001a808c914 __CFRunLoopRun + 1996 (CFRunLoop.c:3149) 23 CoreFoundation 0x00000001a808bcd8 CFRunLoopRunSpecific + 608 (CFRunLoop.c:3420) 24 GraphicsServices 0x00000001ecf3c1a8 GSEventRunModal + 164 (GSEvent.c:2196) 25 UIKitCore 0x00000001aa6c490c -[UIApplication _run] + 888 (UIApplication.m:3713) 26 UIKitCore 0x00000001aa7789d0 UIApplicationMain + 340 (UIApplication.m:5303) 27 SwiftUI 0x00000001ac27c148 closure #1 in KitRendererCommon(_:) + 168 (UIKitApp.swift:51) 28 SwiftUI 0x00000001ac228714 runApp<A>(_:) + 152 (UIKitApp.swift:14) 29 SwiftUI 0x00000001ac2344d0 static App.main() + 132 (App.swift:114) 30 My App 0x00000001001e7bfc static MyApp.$main() + 52 (MyApp.swift:0) 31 My App 0x00000001001e7bfc main + 64 32 dyld 0x00000001cb73de4c start + 2240 (dyldMain.cpp:1298)
2
0
238
3w
SwiftUI NavigationLink freezing when tapped
Any one getting any issues with NavigaitonLink to seemingly innocuous views freezing when tapped on? 1 CPU at 100% memory steadily increasing until app gets killed by the system. Will freeze if any NavigationLink on the view is tapped if certain views are linked to using NavigaitonLink. I note some people have been getting similar freezes if they use @AppStorage, but I'm not using @AppStorage. I do use CoreData tho. tho I have some views that use core data that don't freeze. https://developer.apple.com/forums/thread/708592?page=1#736374022 has anyone experienced similar issues? or know the cause. it doesn't seem to be any of my code because if I pause the debugger it stops on system code.
12
2
6.4k
3w
Can I preview "regular" view in widget extension?
Basically, in my widget/live activity, I want to extract reusable views into a separate file with an isolated view and preview. Dummy example below. I cannot do it because it says "missing previewcontext". The only way I've found is to add the view to my main app target, but I don't want to clutter my main app wiews that only exist in my widgets if I can avoid it. Can this be done somehow? Thoughts appreciated. Dummy example (tried with and without "previewLayout": struct StatusActivityView: View { let status: UserStatusData var body: some View { VStack(alignment: .center) { Text("Dummy example") }.background(.blue).padding(5) } } @available(iOS 16.2, *) struct StatusActivityView_Previews: PreviewProvider { static var previews: some View { let status = WidgetConstants.defaultEntry() return StatusActivityView(status: status).previewLayout(.sizeThatFits) } }
2
0
203
3w
Disable reverb effect in immersive spaces
I'm developing an app where a user can bring a video or content from a WKWebView into an immersive space using SwiftUI attachments on a RealityView. This works just fine, but I'm having some trouble configuring how the audio from the web content should sound in an immersive space. When in windowed mode, content playing sounds just fine and very natural. The spatial audio effect with head tracking is pronounced and adds depth to content with multichannel or Dolby Atmos audio. When I move the same web view into an immersive space however, the audio becomes excessively echoey, as if a large amount of reverb has been put onto the audio. The spatial audio effect is also decreased, and while still there, is no where near as immersive. I've tried the following: Setting all entities in my space to use channel audio, including the web view attachment. for entity in content.entities { entity.channelAudio = ChannelAudioComponent() entity.ambientAudio = nil entity.spatialAudio = nil } Changing the AVAudioSessionSpatialExperience: And I've also tried every soundstage size and anchoring strategy, large works the best, but doesn't remove that reverb. let experience = AVAudioSessionSpatialExperience.headTracked( soundStageSize: .large, anchoringStrategy: .automatic ) try? AVAudioSession.sharedInstance().setIntendedSpatialExperience(experience) I'm also aware of ReverbComponent in visionOS 2 (which I haven't updated to just yet), but ideally I need a way to configure this for visionOS 1 users too. Am I missing something? Surely there's a way for developers to stop the system messing with the audio and applying these effects? A few of my users have complained that the audio sounds considerably worse in my cinema immersive space compared to in a window.
2
0
320
3w
SwiftUI onDrop not working with DropDelegate on iOS18
I am new to SwiftUI, and I wrote a ReorderableForEach struct with onDrag and onDrop, which is working well on iOS17. However it's not wokring on iOS18 beta1 or beta2 on my iPhone or simulator. When I long press the item, nothing happens. When I remove onDrop, I can perform a Drag animation, so I think something wrong with my onDrop code. the whole code: import UIKit import SwiftUI public typealias Reorderable = Identifiable & Equatable struct GridData: Identifiable, Equatable { let id: Int } public struct ReorderableForEach<Item: Reorderable, Content: View, Preview: View>: View { @Binding private var active: Item? @State private var hasChangedLocation = false private let items: [Item] private let content: (Item) -> Content private let preview: ((Item) -> Preview)? private let moveAction: (IndexSet, Int) -> Void private var onDropAction: ((Item) -> Void)? private var allowReorder: Bool public init( _ items: [Item], active: Binding<Item?>, allowReorder: Bool, @ViewBuilder content: @escaping (Item) -> Content, @ViewBuilder preview: @escaping (Item) -> Preview, moveAction: @escaping (IndexSet, Int) -> Void, onDropAction: ((Item) -> Void)? = nil ) { self.items = items self._active = active self.allowReorder = allowReorder self.content = content self.preview = preview self.moveAction = moveAction self.onDropAction = onDropAction } public init( _ items: [Item], active: Binding<Item?>, allowReorder: Bool, @ViewBuilder content: @escaping (Item) -> Content, moveAction: @escaping (IndexSet, Int) -> Void, onDropAction: ((Item) -> Void)? = nil ) where Preview == EmptyView { self.items = items self._active = active self.allowReorder = allowReorder self.content = content self.preview = nil self.moveAction = moveAction self.onDropAction = onDropAction } public var body: some View { ForEach(items) { item in if !allowReorder { contentView(for: item) } else if let preview { contentView(for: item) .onDrag { return dragData(for: item) } preview: { preview(item) } } else { contentView(for: item) .onDrag { return dragData(for: item) } } } } private func contentView(for item: Item) -> some View { content(item) .opacity(active == item && hasChangedLocation ? 0.5 : 1) .onDrop( of: [.text], delegate: ReorderableDragRelocateDelegate( item: item, items: items, active: $active, hasChangedLocation: $hasChangedLocation ) { from, to in withAnimation { moveAction(from, to) } } onDropAction: { item in onDropAction?(item) } ) } private func dragData(for item: Item) -> NSItemProvider { active = item return NSItemProvider(object: "\(item.id)" as NSString) } } struct ReorderableDragRelocateDelegate<Item: Reorderable>: DropDelegate { let item: Item var items: [Item] @Binding var active: Item? @Binding var hasChangedLocation: Bool var moveAction: (IndexSet, Int) -> Void var onDropAction: ((Item) -> Void)? func dropEntered(info: DropInfo) { guard item != active, let current = active else { return } guard let from = items.firstIndex(of: current) else { return } guard let to = items.firstIndex(of: item) else { return } hasChangedLocation = true if items[to] != current { moveAction(IndexSet(integer: from), to > from ? to + 1 : to) } } func dropUpdated(info: DropInfo) -> DropProposal? { DropProposal(operation: .move) } func performDrop(info: DropInfo) -> Bool { hasChangedLocation = false active = nil onDropAction?(item) return true } } struct ReorderableDropOutsideDelegate<Item: Reorderable>: DropDelegate { @Binding var active: Item? func dropUpdated(info: DropInfo) -> DropProposal? { DropProposal(operation: .move) } func performDrop(info: DropInfo) -> Bool { active = nil return true } } public extension View { func reorderableForEachContainer<Item: Reorderable>( active: Binding<Item?> ) -> some View { onDrop(of: [.text], delegate: ReorderableDropOutsideDelegate(active: active)) } } #Preview { ReorderableForEach( (1...10).map { GridData(id: $0) }, active: .constant(nil), allowReorder: true ) { item in Text("Item \(item.id)") .padding() .background(Color.blue) .cornerRadius(8) } preview: { item in Text("Preview \(item.id)") .padding() .background(Color.red) .cornerRadius(8) } moveAction: { from, to in print("Move from \(from) to \(to)") } } Am I missing something or this is a bug on iOS18? Thanks in advance.
1
2
167
3w
macOS SwiftUI Sheets are no longer resizable (Xcode 16 beta2)
For whatever reason SwiftUI sheets don't seem to be resizable anymore. The exact same code/project produces resizable Sheets in XCode 15.4 but unresizable ones with Swift included in Xcode 16 beta 2. Tried explicitly providing .fixedSize(horizontal false, vertical: false) everywhere humanly possible hoping for a fix but sheets are still stuck at an awkward size (turns out be the minWidth/minHeight if I provide in .frame).
4
1
211
3w
Swift FileManager.default.copyItem(at: URL, to: URL) folder permission error
I'm working on creating a tiny app that copies a random sampling of files from a source folder to a destination folder: https://github.com/belovachap/Select-Random-Files-Mac I choose folders in my user's Documents folder, am able to get the random sampling of files but then run into permission errors when trying to copy to the destination folder. I've tried adding a call to startAccessingSecurityScopedResource on the destination URL but it doesn't seem to help. Is this having the same problems on anyone else's computer??
1
0
187
3w
How to animate NavigationSplitView's detailView column.
Having a traditional 'NavigationSplitView' setup, I am looking for a way to animate it the same as the sidebarView, where there is a button to toggle and it animates by sliding out from the right side of the view, however the closest I have gotten was manipulating the 'navigationSplitViewColumnWidth' but that always results in the view instantly appearing / disappearing. I am using SwiftUI for a MacOS specific app. Here is just a general idea of what I am currently doing, it is by no means a reflection of my real code but serves the purpose of this example. struct ContentView: View { @State private var columnWidth: CGFloat = 300 var body: some View { NavigationSplitView { List { NavigationLink(destination: DetailView(item: "Item 1")) { Text("Item 1") } NavigationLink(destination: DetailView(item: "Item 2")) { Text("Item 2") } NavigationLink(destination: DetailView(item: "Item 3")) { Text("Item 3") } } .navigationTitle("Items") } detail: { VStack { DetailView(item: "Select an item") Button(action: toggleColumnWidth) { Text(columnWidth == 300 ? "Collapse" : "Expand") } .padding() } } .navigationSplitViewColumnWidth(columnWidth) } private func toggleColumnWidth() { withAnimation { columnWidth = columnWidth == 300 ? 0 : 300 } } } struct DetailView: View { var item: String var body: some View { Text("Detail view for \(item)") .navigationTitle(item) .padding() } } @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } }
1
0
337
3w
iOS DisclosureGroup content clipping
I have a SwiftUI page that I want to simplify by showing basic information by default, and putting the additional info behind a "Details" DisclosureGroup for advanced users. I started by laying out all the components and breaking things into individual Views. These all are laid out and look fine. Then I took several of them and added them inside a DisclosureGroupView. But all of a sudden, the views inside started getting crunched together and the contents of the DisclosureGroup got clipped about 2/3 of the way down the page. The problem I'm trying to solve is how to show everything inside the DIsclosureGroup. The top-level View looks like this: VStack { FirstItemView() SecondView() DetailView() // <- Shows disclosure arrow } Where DetailView is: struct DetailView: View { @State var isExpanded = true var body: some View { GeometryReader { geometry in DisclosureGroup("Details", isExpanded: $isExpanded) { ThirdRowView() Spacer() FourthRowView() VStack { FifthRowWithChartView() CaptionLabelView(label: "Third", iconName: "chart.bar.xaxis") } } } } } The FifthRowWithChartView is half-clipped. One thing that might contribute is that there is a Chart view at the bottom of this page. I've tried setting the width and height of the DisclosureGroup based on the height returned by the GeometryReader, but that didn't do anything. This is all on iOS 17.6, testing on an iPhone 15ProMax. Any tips or tricks are most appreciated.
2
0
219
3w
Help, can't use TabView
Hi, I learned swift only a few weeks ago, and im trying to make a TabView in Xcode. But, it shows only one item! I've already made this work in other apps, but I can't get it working here! import SwiftUI struct tabs: View { var body: some View { TabView { ContentView() .tabItem { Image(systemName: "house.circle.fill") Text("Home") Settngs() .tabItem { Image(systemName:"gear.circle.fill") Text("Settings") } } } } } #Preview { tabs() } and also, I checked "settngs()" and its my name
1
0
197
3w