Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.

All subtopics

Post

Replies

Boosts

Views

Activity

UIPrintInteractionController IOS 18 issue on shared.
Only IOS 18+ bug. After tap share on UIPrintInteractionController - crash. So: #0 0x00000001bc38edf4 in _realizeSettingsExtension.cold.5 () #1 0x00000001bc310ed0 in _realizeSettingsExtension () #2 0x00000001bc33d100 in _ingestPropertiesFromSettingsSubclass () #3 0x00000001bc33be50 in __FBSIngestSubclassProperties_block_invoke () #4 0x00000001bc33bd7c in FBSIngestSubclassProperties () #5 0x00000001bc33d814 in FBSSettingForLegacySelector () #6 0x00000001bc30ecf8 in FBSSettingForSelector () #7 0x00000001bc350d98 in -[FBSMutableSceneSettings addPropagatedProperty:] () #8 0x00000001a64bae88 in __58-[_UISceneHostingController createSceneWithConfiguration:]_block_invoke_3 () #9 0x00000001c5bc16ec in -[FBScene _joinUpdate:block:completion:] () #10 0x00000001a64bab9c in -[_UISceneHostingController createSceneWithConfiguration:] () #11 0x00000001a64ba838 in -[_UISceneHostingController initWithAdvancedConfiguration:] () #12 0x00000001a64ba8cc in -[_UISceneHostingController initWithProcessIdentity:sceneSpecification:] () #13 0x00000001c05a8bd0 in -[SHSheetRemoteScene setupSceneHosting] () #14 0x00000001c05a88d0 in -[SHSheetRemoteScene activate] () #15 0x00000001c05f2e88 in -[SHSheetInteractor startSession] () #16 0x00000001c05ebc08 in -[SHSheetPresenter initWithRouter:interactor:] () #17 0x00000001c05de3c8 in +[SHSheetFactory createMainPresenterWithContext:] () #18 0x00000001c05d4dec in -[UIActivityViewController _createMainPresenterIfNeeded] () #19 0x00000001c05d6320 in -[UIActivityViewController _viewControllerPresentationDidInitiate] () #20 0x00000001a5a109c4 in -[UIViewController _presentViewController:withAnimationController:completion:] () #21 0x00000001a5a1311c in __63-[UIViewController _presentViewController:animated:completion:]_block_invoke () #22 0x00000001a5a0d248 in -[UIViewController _performCoordinatedPresentOrDismiss:animated:] () #23 0x00000001a5a0ceb4 in -[UIViewController _presentViewController:animated:completion:] () #24 0x00000001a5a0ccc0 in -[UIViewController presentViewController:animated:completion:] () #25 0x00000002001f3660 in -[UIPrintPanelViewController showSharePanelForPDFURL:] () In log throwing an error (I'm not 100% sure that is related - but last class in stack trace the same): failure in void _realizeSettingsExtension(__unsafe_unretained Class, __unsafe_unretained Class) (FBSSceneExtension.m:502) : could not convert "1" to an integer What I have is that big project with a lot of dependencies and etc.. Trying on clear project and it worked. (sharing simple local image with url). Testing on my project: With no controllers at all - check. With different approaches (htm content; pdf data, image local url) - check. With UIActivityViewController - check With day of UIPrintInteractionController creation (not a thread/related issue) - check. No other work can be done from my side (except rewrite 10years project). Help me please to debug it from private api prospective as I have no Idea what is happening. (trying to remove all appearances and all dependency - not easy task). Thanks
0
0
135
2w
How do you control the location of the menu in a UIContextMenu ?
class Coordinator: NSObject, UIContextMenuInteractionDelegate, ContextMenuManagerDelegate { var container: ContextMenuContainer var auxiliaryContent: AuxiliaryContent var menuItems: () -> [UIMenuElement] init(container: ContextMenuContainer) { self.container = container self.auxiliaryContent = container.auxiliaryContent self.menuItems = container.menuItems super.init() } func contextMenuInteraction( _ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint ) -> UIContextMenuConfiguration? { container.viewModel.contextMenuManager?.notifyOnContextMenuInteraction( interaction, configurationForMenuAtLocation: location ) return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { [weak self] _ in UIMenu(title: "", children: self?.menuItems() ?? []) } } func contextMenuInteraction( _ interaction: UIContextMenuInteraction, willDisplayMenuFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating? ) { container.viewModel.contextMenuManager?.notifyOnContextMenuInteraction( interaction, willDisplayMenuFor: configuration, animator: animator ) } func contextMenuInteraction( _ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating? ) { container.viewModel.contextMenuManager?.notifyOnContextMenuInteraction( interaction, willEndFor: configuration, animator: animator ) } func contextMenuInteraction( _ interaction: UIContextMenuInteraction, previewForHighlightingMenuWithConfiguration configuration: UIContextMenuConfiguration ) -> UITargetedPreview? { guard let targetView = interaction.view else { return nil } let bubbleWithTail = BubbleWithTailPath() let customPath = bubbleWithTail.path(in: targetView.bounds) let parameters = UIPreviewParameters() parameters.visiblePath = customPath return UITargetedPreview( view: targetView, parameters: parameters ) } func onRequestMenuAuxiliaryPreview(sender: ContextMenuManager) -> UIView? { let hostingController = UIHostingController(rootView: auxiliaryContent) hostingController.view.backgroundColor = .clear return hostingController.view } } i am trying to recreate apple's iMessage tapback reaction context menu. i have figured out how to attach an auxiliary view to the view with the menu, however the menu itself varies in position. if i bring up the context menu on a view below half the screen height, the menu appears above the view. else, it appears below. i need it to always be below.
0
0
112
2w
Context Menu Position and Preview Fade
By default, when using Context Menu the menu will flip positions to be above or below the content based on the current screen position. Many apps however, tend to keep the menu anchored to the bottom of the content it is associated with and move the content up to fit the menu (iMessage messages for example). In order to get this behavior, where the menu is always anchored to the bottom and the content "shifts up" to make space you have to use a custom preview by passing a previewProvider. So to get the desired behavior you can use a preview that is the same content as the original view. However, when you do this there is a small fade in animation that gets added and since the content of the original view and preview is the same this appears as a flicker. Is there any way to disable this fade animation or force anchor the menu to the bottom when using the standard preview?
0
0
119
2w
NSTextView Contents Disappear When Ruler shown
I have a problem with rulers in an NSTextView. My code has worked fine from about Sierra (10.12), up to Ventura (13), it stopped working in Sonoma and continues to fail in the same way in Sequoia (14 - 15). When I display the ruler, the contents of the text area disappears leaving just a pale grey background. When I make the ruler invisible again the text reappears. No errors are reported (at compile or run time). I have tried adding refreshes of the text view in various places with no result. I have (for Sequoia) used Interface Builder to force the text view to use TextKit 1, also with no success. I’m at a loss as to how to proceed because I’m not getting any diagnostics, simply changed behaviour. My app provides a programming IDE. It includes a program editor that uses line numbering code for an NSTextView from WWDC/Noodlesoft. The line numbers are shown in the ruler which is sometimes visible and sometimes not. When I display the ruler, I also set the main text to not editable but removing this setting does not appear to make any difference. Any suggestions would be very wel PLATFORM AND VERSION macOS, Objective C Development environment: Xcode Version 16.0 (16A242d) [and previously Xcode 15], macOS All releases of Sonoma and Sequoia 15.0.1 (24A348) Run-time configuration: macOS Sequoia 15.0.1 (24A348) The sequence is essentially: [editTextView setEditable:NO]; [self showRulerIn:editTextView visible:YES]; Using: -(void)showRulerIn:(NSTextView*)editorTv visible:(BOOL)vis { NSScrollView *scrollV = [editorTv enclosingScrollView]; NSClipView *clipV = [scrollV contentView]; MBEditorTextView *textView = (MBEditorTextView*)[scrollV documentView]; // The actual text [scrollV setRulersVisible:vis]; // Creates the ruler if necessary … return; } LINE NUMBERING CODE The line number code comes from 2 sources but they are so similar that one must be derived from the other: Apple’s WWDC 2010 code at: https://download.developer.apple.com/videos/wwdc_2010__hd/session_114__advanced_cocoa_text_tips_and_tricks.mov Noodlesoft's code at: https://www.noodlesoft.com/blog/2008/10/05/displaying-line-numbers-with-nstextview/
2
0
178
2w
MacOS SwiftUI: Is it impossible to clear a Table selection?
I figured it would be as simple as changing the selection variable back to nil, but that seemingly has no effect. The Table row stays selected, and if I press on it again, it won't trigger my .navigationDestination(). How can I resolve this? I found another post asking the same thing, with no resolution. The only way I can clear it is by clicking with my mouse somewhere else. @State private var selectedID: UUID? = nil Table(tableData, selection: $selectedID, sortOrder: $sortOrder)... .navigationDestination(item: $selectedID, destination: { id in if let cycle = cycles.first(where: {$0.id == id}) { CycleDetailView(cycle: cycle) .onDisappear(perform: { selectedID = nil }) } })
2
0
141
2w
Page view in SwiftUI
I have an app for musicians that works with Songs and Setlists. The logical structure is as follows: A Setlist contains Songs. A Song has Sections, which include Lines (chords & lyrics). I want to view my Setlist in a "Page View," similar to a book where I can swipe through pages. In this view, the Song Sections are wrapped into columns to save screen space. I use a ColumnsLayout to calculate and render the columns, and then a SplitToPages modifier to divide these columns into pages. Problem: The TabView sometimes behaves unexpectedly when a song spans multiple pages during rendering. This results in a transition that is either not smooth or stops between songs. Is there a better way to implement this behavior? Any advice would be greatly appreciated. struct TestPageView: View { struct SongWithSections: Identifiable { var id = UUID() var title: String var section: [String] } var songSetlistSample: [SongWithSections] { var songs: [SongWithSections] = [] //songs for i in 0...3 { var sections: [String] = [] for _ in 0...20 { sections.append(randomSection() + "\n\n") } songs.append(SongWithSections(title: "Song \(i)", section: sections)) } return songs } func randomSection() -> String { var randomSection = "" for _ in 0...15 { randomSection.append(String((0..<Int.random(in: 3..<10)).map{ _ in "abcdefghijklmnopqrstuvwxyz".randomElement()! }) + " ") } return randomSection } var body: some View { GeometryReader {geo in TabView { ForEach(songSetlistSample, id:\.id) {song in let columnWidth = geo.size.width / 2 //song ColumnsLayout(columns: 2, columnWidth: columnWidth, height: geo.size.height) { Text(song.title) .font(.largeTitle) ForEach(song.section, id:\.self) {section in Text(section) } } .modifier(SplitToPages(pageWidth: geo.size.width, id: song.id)) } } .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) } } } public struct ColumnsLayout: Layout { var columns: Int let columnWidth: CGFloat let height: CGFloat let spacing: CGFloat = 10 public static var layoutProperties: LayoutProperties { var properties = LayoutProperties() properties.stackOrientation = .vertical return properties } struct Column { var elements: [(index: Int, size: CGSize, yOffset: CGFloat)] = [] var xOffset: CGFloat = .zero var height: CGFloat = .zero } public func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) -> CGSize { let columns = arrangeColumns(proposal: proposal, subviews: subviews, cache: &cache) guard let maxHeight = columns.map({ $0.height}).max() else {return CGSize.zero} let width = Double(columns.count) * self.columnWidth return CGSize(width: width, height: maxHeight) } public func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) { let columns = arrangeColumns(proposal: proposal, subviews: subviews, cache: &cache) for column in columns { for element in column.elements { let x: CGFloat = column.xOffset let y: CGFloat = element.yOffset let point = CGPoint(x: x + bounds.minX, y: y + bounds.minY) let proposal = ProposedViewSize(width: self.columnWidth, height: proposal.height ?? 100) subviews[element.index].place(at: point, anchor: .topLeading, proposal: proposal) } } } private func arrangeColumns(proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) -> [Column] { var currentColumn = Column() var columns = [Column]() var colNumber = 0 var currentY = 0.0 for index in subviews.indices { let proposal = ProposedViewSize(width: self.columnWidth, height: proposal.height ?? 100) let size = subviews[index].sizeThatFits(proposal) let spacing = size.height > 0 ? spacing : 0 if currentY + size.height > height { currentColumn.height = currentY columns.append(currentColumn) colNumber += 1 currentColumn = Column() currentColumn.xOffset = Double(colNumber) * (self.columnWidth) currentY = 0.0 } currentColumn.elements.append((index, size, currentY)) currentY += size.height + spacing } currentColumn.height = currentY columns.append(currentColumn) return columns } } struct SplitToPages: ViewModifier { let pageWidth: CGFloat let id: UUID @State private var pages = 1 func body(content: Content) -> some View { let contentWithGeometry = content .background( GeometryReader { geometryProxy in Color.clear .onChange(of: geometryProxy.size) {newSize in guard newSize.width > 0, pageWidth > 0 else {return} pages = Int(ceil(newSize.width / pageWidth)) } .onAppear { guard geometryProxy.size.width > 0, pageWidth > 0 else {return} pages = Int(ceil(geometryProxy.size.width / pageWidth)) } }) Group { ForEach(0..<pages, id:\.self) {p in ZStack(alignment: .topLeading) { contentWithGeometry .offset(x: -Double(p) * pageWidth, y: 0) .frame(width: pageWidth, alignment: .leading) VStack { Spacer() HStack { Spacer() Text("\(p + 1) of \(pages)") .padding([.leading, .trailing]) } } } .id(id.description + p.description) } } } }
0
0
146
2w
CMMotionManager level meter inaccurate
I want to add a "bubble horizon" to a camera application to show if the user is keeping their phone level. For this, I'm using the Motion Attitude functionality of CMMotionManager. However, the output I'm getting is very inaccurate. I'm comparing it with Apple's own Measure app which is dead accurate, so the sensors are working fine. My own readings seem to be several degrees off. Am I missing some calibration step or something? - (void)processDeviceMotion:(CMDeviceMotion *)motion { // use quaternions to avoid Gimbal Lock CMQuaternion quat = motion.attitude.quaternion; // calculate roll in degrees double roll = atan2( 2 * ( quat.w * quat.x + quat.y * quat.z ), 1 - 2 * ( quat.x * quat.x + quat.y * quat.y ) ); roll = radiansToDegrees( roll ); NSLog( @"Roll: %f", roll ); }
0
0
117
2w
Struggling with NSScrollView
I'm still discovering swift and the various frameworks. So I'm now trying to create scrolling composition with a grid - containing images - and an NSStackView at on top. However, I'm running into a problem that might seem stupid, but when I try to wrap my NSCollectionView in another NSView and pointing the scrollView.documentView to, I can't scroll anymore... Even though it works fine when I set the scrollView.documentView to the NSCollectionView directly. Working case: override func viewDidLoad() { super.viewDidLoad() scrollView = NSScrollView(frame: .zero) scrollView.hasVerticalScroller = true scrollView.hasHorizontalScroller = false scrollView.scrollerStyle = .overlay scrollView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(scrollView) vStack = NSStackView(frame: .zero) vStack.orientation = .vertical vStack.spacing = 12 * 2 vStack.translatesAutoresizingMaskIntoConstraints = false let hStack = NSStackView() hStack.orientation = .horizontal hStack.spacing = 12 hStack.translatesAutoresizingMaskIntoConstraints = false let label1 = NSTextField(labelWithString: "Collection") hStack.addArrangedSubview(label1) let layout = PinterestLayout() layout.delegate = self collectionView = NSCollectionView(frame: .zero) collectionView.collectionViewLayout = layout collectionView.dataSource = self collectionView.delegate = self collectionView .register( ArtCardCell.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("ArtCardCell") ) collectionView.backgroundColors = [.BG] collectionView.translatesAutoresizingMaskIntoConstraints = false // vStack.addArrangedSubview(hStack) // vStack.addArrangedSubview(collectionView) scrollView.documentView = collectionView NSLayoutConstraint.activate([ scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), scrollView.topAnchor.constraint(equalTo: view.topAnchor), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), // vStack.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), // vStack.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), // vStack.topAnchor.constraint(equalTo: scrollView.topAnchor), // vStack.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), // vStack.widthAnchor.constraint(equalTo: scrollView.widthAnchor), collectionView.widthAnchor.constraint(equalTo: scrollView.widthAnchor), // vStack.arrangedSubviews[0].leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 12), // vStack.arrangedSubviews[0].trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -12), // vStack.arrangedSubviews[0].topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 80) ]) collectionView.postsBoundsChangedNotifications = true NotificationCenter.default.addObserver(self, selector: #selector(didScroll(_:)), name: NSView.boundsDidChangeNotification, object: collectionView.enclosingScrollView?.contentView ) } collectionView height: 3549.0 ScrollView height: 628.0 StackView height: -- Dysfunctional case: override func viewDidLoad() { super.viewDidLoad() scrollView = NSScrollView(frame: .zero) scrollView.hasVerticalScroller = true scrollView.hasHorizontalScroller = false scrollView.scrollerStyle = .overlay scrollView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(scrollView) vStack = NSStackView(frame: .zero) vStack.orientation = .vertical vStack.spacing = 12 * 2 vStack.translatesAutoresizingMaskIntoConstraints = false let hStack = NSStackView() hStack.orientation = .horizontal hStack.spacing = 12 hStack.translatesAutoresizingMaskIntoConstraints = false let label1 = NSTextField(labelWithString: "Collection") hStack.addArrangedSubview(label1) let layout = PinterestLayout() layout.delegate = self collectionView = NSCollectionView(frame: .zero) collectionView.collectionViewLayout = layout collectionView.dataSource = self collectionView.delegate = self collectionView .register( ArtCardCell.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("ArtCardCell") ) collectionView.backgroundColors = [.BG] collectionView.translatesAutoresizingMaskIntoConstraints = false vStack.addArrangedSubview(hStack) vStack.addArrangedSubview(collectionView) scrollView.documentView = vStack NSLayoutConstraint.activate([ scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), scrollView.topAnchor.constraint(equalTo: view.topAnchor), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), vStack.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), vStack.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), vStack.topAnchor.constraint(equalTo: scrollView.topAnchor), vStack.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), vStack.widthAnchor.constraint(equalTo: scrollView.widthAnchor), collectionView.widthAnchor.constraint(equalTo: scrollView.widthAnchor), vStack.arrangedSubviews[0].leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 12), vStack.arrangedSubviews[0].trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -12), vStack.arrangedSubviews[0].topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 80) ]) } collectionView height: 508.0 ScrollView height: 628.0 StackView height: 628.0
0
0
118
2w
App Crashes on QuartzCore: CA::Layer::layout_if_needed(CA::Transaction*) + 504
I have facing an above crash for many users device running on iOS 17.6.1 mostly on iPad devices. I'm not sure why this happening only in 17.X. In Xcode Organizer unable to see this crash in any devices running on OS 18.x. Our app crashes got spiked due to this. I am unable to fix or reproduce the same. The crash log is not pointing to our app code to find the root cause and fix this issue. Have attached the crash log in this post also the crash log roles have mixed values Background &amp;amp; Foreground. But most of the crash is in background. Is this any crash related to system and that only solved by OS update? I have updated the app using Xcode 16 and 16.1 still facing this crash unable to symbolicate the crash report as well. Any ideas/solution how to solve this or how to proceed further. Have attached the entire crash log below. RoleBackgroundCrash.crash RoleForeGroundCrash.crash
0
0
145
2w
MapkitJS - not able to click on PointOfInterest and use it for actions
Hi, Have been trying to work with MapkitJS for a website, but I'm stumped on once basic capability: I want to be able to click on a point of interest, and perform some actions such as: Get its coordinates Attach an annotation to it (e.g. a callout) In my code, PointOfInterest's are selectable: map.selectableMapFeatures = [ mapkit.MapFeatureType.PointOfInterest, ]; But when I click on one, I do see the marker pop up but nothing else (which is not much help since there is no additional information in the marker itself). I see no event getting triggered that I can do something with. I am using an event listener as follows: map.addEventListener('single-tap', (event) => { const coordinate = map.convertPointOnPageToCoordinate(event.pointOnPage); console.log('Map tapped at:', coordinate); console.log('Map tapped event:', event); ... I guess I have to grab the Place ID somehow but I don't know how to. Thanks for any help.
0
0
154
2w
Defer system gestures in a WatchKit app
Hi, I'm making a WatchKit game app with SpriteKit and Objective-C, and I'm encountering an annoyance where system gestures, namely long-pressing the top and bottom edges to pull Notification/Control Center, interfere with the controls of the game. In iOS, this can be mitigated by using overriding preferredScreenEdgesDeferringSystemGestures in UIViewController, but I couldn't find any equivalent API in any WatchKit class, and searching for similar symbols only yielded a single private API (-[_UISystemAppearanceManager screenEdgesDeferringSystemGestures]) that isn't ever called on watchOS. Any idea how to achieve a similar effect on watchOS?
1
0
174
2w
SwiftUI Lists down arrow handling broken
This has been broken for over 5 years now. I see 2 different behaviors in 2 different SwiftUI apps. This makes SwiftUI not ready for prime time apps, but I just have tools right now. The VStack { List } doesn't scroll to the item in a long list. The selection moves to the next item in the list, but can't see it. This is just basic UI functionality of a list. UIListView doesn't have this issue. The NavigationView { List { NavigationLink }} wraps around back to the top of the list when pressing down arrow past the last visible item, but there are plenty more list items to visit.
3
0
180
2w
Screen on Apple watch turn off even when "Always On" is active
Our company has developed a product available, which measures body composition. During the measurement process, lasting 40 seconds, we require the device screen to remain illuminated. We are actively using the "Always On" feature and have set the timer on the watch to 70 minutes to prevent the screen from dimming. However, we are encountering issues where the screen may still turn off during the measurement. Could you please provide guidance on how to keep the screen active with backlighting across all Apple Watch models during measurements?
2
0
187
2w
Issue with Margin During Navigation Transition in iOS 18+
The new .navigationTransition feature introduced in SwiftUI for iOS 18+ offers an impressive animated screen transition. However, during the transition, the parent view shrinks, leaving a white margin (or black in dark mode) around the edges. If the background color of the parent view matches this margin color, it appears seamless. However, as shown in the attached example, when using a custom color or gradient background, the margin becomes visually disruptive. Is there a way to address this? import SwiftUI struct ContentView: View { @Namespace var namespace var body: some View { NavigationStack { Form { NavigationLink { ZStack { Color.yellow.ignoresSafeArea() Text("Detail View") } .navigationTitle("Transition") .navigationTransition(.zoom(sourceID: "hellow", in: namespace)) } label: { Text("Open") .font(.largeTitle) .matchedTransitionSource(id: "hellow", in: namespace) } } .scrollContentBackground(.hidden) .background(Color.mint.ignoresSafeArea()) } } } #Preview { ContentView() } Applying .ignoreSafeArea() to the background view doesn’t seem to resolve the issue, which suggests this margin might not be related to the safe area. Any insights or solutions would be greatly appreciated.
1
0
153
2w
SwiftUI Gestures: Sequenced Long Press and Drag
In creating a sequenced gesture combining a LongPressGesture and a DragGesture, I found that the combined gesture exhibits two problems: The @GestureState does not properly update as the gesture progresses through its phases. Specifically, the updating(_:body:) closure (documented here) is only ever executed during the drag interaction. Long presses and drag-releases do not call the updating(_:body:) closure. Upon completing the long press gesture and activating the drag gesture, the drag gesture remains empty until the finger or cursor has moved. The expected behavior is for the drag gesture to begin even when its translation is of size .zero. This second problem – the nonexistence of a drag gesture once the long press has completed – prevents access to the location of the long-press-then-drag. Access to this location is critical for displaying to the user that the drag interaction has commenced. The below code is based on Apple's example presented here. I've highlighted the failure points in the code with // *. My questions are as follows: What is required to properly update the gesture state? Is it possible to have a viable drag gesture immediately upon fulfilling the long press gesture, even with a translation of .zero? Alternatively to the above question, is there a way to gain access to the location of the long press gesture? import SwiftUI import Charts enum DragState { case inactive case pressing case dragging(translation: CGSize) var isDragging: Bool { switch self { case .inactive, .pressing: return false case .dragging: return true } } } struct ChartGestureOverlay<Value: Comparable & Hashable>: View { @Binding var highlightedValue: Value? let chartProxy: ChartProxy let valueFromChartProxy: (CGFloat, ChartProxy) -> Value? let onDragChange: (DragState) -> Void @GestureState private var dragState = DragState.inactive var body: some View { Rectangle() .fill(Color.clear) .contentShape(Rectangle()) .onTapGesture { location in if let newValue = valueFromChartProxy(location.x, chartProxy) { highlightedValue = newValue } } .gesture(longPressAndDrag) } private var longPressAndDrag: some Gesture { let longPress = LongPressGesture(minimumDuration: 0.2) let drag = DragGesture(minimumDistance: .zero) .onChanged { value in if let newValue = valueFromChartProxy(value.location.x, chartProxy) { highlightedValue = newValue } } return longPress.sequenced(before: drag) .updating($dragState) { value, gestureState, _ in switch value { case .first(true): // * This is never called gestureState = .pressing case .second(true, let drag): // * Drag is often nil // * When drag is nil, we lack access to the location gestureState = .dragging(translation: drag?.translation ?? .zero) default: // * This is never called gestureState = .inactive } onDragChange(gestureState) } } } struct DataPoint: Identifiable { let id = UUID() let category: String let value: Double } struct ContentView: View { let dataPoints = [ DataPoint(category: "A", value: 5), DataPoint(category: "B", value: 3), DataPoint(category: "C", value: 8), DataPoint(category: "D", value: 2), DataPoint(category: "E", value: 7) ] @State private var highlightedCategory: String? = nil @State private var dragState = DragState.inactive var body: some View { VStack { Text("Bar Chart with Gesture Interaction") .font(.headline) .padding() Chart { ForEach(dataPoints) { dataPoint in BarMark( x: .value("Category", dataPoint.category), y: .value("Value", dataPoint.value) ) .foregroundStyle(highlightedCategory == dataPoint.category ? Color.red : Color.gray) .annotation(position: .top) { if highlightedCategory == dataPoint.category { Text("\(dataPoint.value, specifier: "%.1f")") .font(.caption) .foregroundColor(.primary) } } } } .frame(height: 300) .chartOverlay { chartProxy in ChartGestureOverlay<String>( highlightedValue: $highlightedCategory, chartProxy: chartProxy, valueFromChartProxy: { xPosition, chartProxy in if let category: String = chartProxy.value(atX: xPosition) { return category } return nil }, onDragChange: { newDragState in dragState = newDragState } ) } .onChange(of: highlightedCategory, { oldCategory, newCategory in }) } .padding() } } #Preview { ContentView() } Thank you!
3
0
245
2w
Help Loading an External CSV File on iOS in Swift
Hi everyone! I’m fairly new to Swift and currently working on a small iOS app in SwiftUI. The app is able to load a CSV file embedded in the Xcode project (using Bundle.main.path(forResource:)), and everything works well with that. Now, I want to take it a step further by allowing the app to load an external CSV file located in the iPhone’s directories (like “Documents” or “Downloads”). However, I’m struggling to make it work. I tried using a DocumentPicker to select the CSV file, and I believe I’m passing the file URL correctly, but the app keeps reading only the embedded file instead of the one selected by the user. Could anyone offer guidance on how to properly set up loading an external CSV file? I’m still learning, so any suggestions or examples would be really appreciated! Thanks a lot in advance for the help! Here’s the code that isn’t working as expected: import Foundation struct Product: Identifiable { let id = UUID() var codice: String var descrizione: String var prezzo: Double var installazione: Double var trasporto: Double } class ProductViewModel: ObservableObject { @Published var products: [Product] = [] @Published var filteredProducts: [Product] = [] func loadCSV(from url: URL) { products = [] do { let data = try String(contentsOf: url) let lines = data.components(separatedBy: "\n") // Legge e processa ogni riga del CSV (saltando la prima riga se è l'intestazione) for line in lines.dropFirst() { let values = line.components(separatedBy: ";") // Assicurati che ci siano abbastanza colonne e gestisci i valori mancanti if values.count &gt;= 5 { let codice = values[0].trimmingCharacters(in: .whitespaces) let descrizione = values[1].trimmingCharacters(in: .whitespaces) let prezzo = parseEuropeanDouble(values[2]) ?? 0.0 let installazione = parseEuropeanDouble(values[3].isEmpty ? "0,00" : values[3]) ?? 0.0 let trasporto = parseEuropeanDouble(values[4].isEmpty ? "0,00" : values[4]) ?? 0.0 let product = Product( codice: codice, descrizione: descrizione, prezzo: prezzo, installazione: installazione, trasporto: trasporto ) products.append(product) } } filteredProducts = products } catch { print("Errore nel caricamento del CSV: \(error)") } } private func parseEuropeanDouble(_ value: String) -&gt; Double? { let formatter = NumberFormatter() formatter.locale = Locale(identifier: "it_IT") formatter.numberStyle = .decimal return formatter.number(from: value)?.doubleValue } } struct ContentView: View { @StateObject var viewModel = ProductViewModel() @State private var showFilePicker = false var body: some View { VStack { Button("Carica file CSV") { showFilePicker = true } .fileImporter(isPresented: $showFilePicker, allowedContentTypes: [.commaSeparatedText]) { result in switch result { case .success(let url): viewModel.loadCSV(from: url) case .failure(let error): print("Errore nel caricamento del file: \(error.localizedDescription)") } } List(viewModel.filteredProducts) { product in VStack(alignment: .leading) { Text("Codice: \(product.codice)") Text("Descrizione: \(product.descrizione)") Text("Prezzo Lordo: €\(String(format: "%.2f", product.prezzo))") Text("Installazione: €\(String(format: "%.2f", product.installazione))") Text("Trasporto: €\(String(format: "%.2f", product.trasporto))") } } } .padding() } }
1
0
196
2w
FocusState and pickers error
Hello, since the last version of iOS and WatchOS I have a problem with this code. This is the minimal version of the code, it have two pickers inside a view of a WatchOS App. The problem its with the focus, I can't change the focus from the first picker to the second one. As I said before, it was working perfectly in WatchOS 10.0 but in 11 the problems started. struct ParentView: View { @FocusState private var focusedField: String? var body: some View { VStack { ChildView1(focusedField: $focusedField) ChildView2(focusedField: $focusedField) } } } struct ChildView1: View { @FocusState.Binding var focusedField: String? @State private var selectedValue: Int = 0 var body: some View { Picker("First Picker", selection: $selectedValue) { ForEach(0..<5) { index in Text("Option \(index)").tag("child\(index)") } }.pickerStyle(WheelPickerStyle()).focused($focusedField, equals: "first") } } struct ChildView2: View { @FocusState.Binding var focusedField: String? @State private var selectedValue: Int = 0 var body: some View { Picker("Second Picker", selection: $selectedValue) { ForEach(0..<5) { index in Text("Option \(index)").tag("childTwo\(index)") } }.pickerStyle(WheelPickerStyle()).focused($focusedField, equals: "second") } } When you do vertical scrolling on the second picker, the focus should be on it, but it dosnt anything. I try even do manually, setting the focusState to the second one, but it sets itself to nil. I hope that you can help me, thanks!
3
0
246
2w