When I present a view controller, whose view is a SwiftUI View, via presentAsModalWindow(_:) the presented window is no longer centered horizontally to the screen, but rather its origin is there. I know this issue occurs for macOS 15.2+, but can't tell if it is from 15.0+. I couldn't find any documentation on why was this changed.
Here's an example code that represents my architecture:
class RootViewController: NSViewController {
private lazy var button: NSButton = NSButton(
title: "Present",
target: self,
action: #selector(presentView))
override func viewDidLoad() {
super.viewDidLoad()
// Add button to tree
}
@objc func presentView() {
presentAsModalWindow(PresentedViewController())
}
}
class PresentedViewController: NSViewController {
override loadView() {
view = NSHostingView(rootView: MyView())
}
}
struct MyView: View {
/* impl */
}
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.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have a UILabel subclass showing NSAttributedString in which I need to draw a rounded rectangle background color around links:
import UIKit
class MyLabel: UILabel {
private var linkRects = [[CGRect]]()
private let layoutManager = NSLayoutManager()
private let textContainer = NSTextContainer(size: .zero)
private let textStorage = NSTextStorage()
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
linkRects.forEach { rects in
rects.forEach { linkPieceRect in
path.append(UIBezierPath(roundedRect: linkPieceRect, cornerRadius: 2))
}
}
UIColor.systemGreen.withAlphaComponent(0.4).setFill()
path.fill()
super.draw(rect)
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
private func setup() {
numberOfLines = 0
adjustsFontForContentSizeCategory = true
isUserInteractionEnabled = true
lineBreakMode = .byWordWrapping
contentMode = .redraw
clearsContextBeforeDrawing = true
isMultipleTouchEnabled = false
backgroundColor = .red.withAlphaComponent(0.1)
textContainer.lineFragmentPadding = 0
textContainer.maximumNumberOfLines = numberOfLines
textContainer.lineBreakMode = lineBreakMode
textContainer.layoutManager = layoutManager
layoutManager.textStorage = textStorage
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
}
override func layoutSubviews() {
super.layoutSubviews()
calculateRects()
}
private func calculateRects(){
linkRects.removeAll()
guard let attributedString = attributedText else {
return
}
textStorage.setAttributedString(attributedString)
let labelSize = frame.size
textContainer.size = labelSize
layoutManager.ensureLayout(for: textContainer)
let textBoundingBox = layoutManager.usedRect(for: textContainer)
print("labelSize: \(labelSize)")
print("textBoundingBox: \(textBoundingBox)")
var wholeLineRanges = [NSRange]()
layoutManager.enumerateLineFragments(forGlyphRange: NSRange(0 ..< layoutManager.numberOfGlyphs)) { _, rect, _, range, _ in
wholeLineRanges.append(range)
print("Whole line: \(rect), \(range)")
}
attributedString.enumerateAttribute(.link, in: NSRange(location: 0, length: attributedString.length)) { value, clickableRange, _ in
if value != nil {
var rectsForCurrentLink = [CGRect]()
wholeLineRanges.forEach { wholeLineRange in
if let linkPartIntersection = wholeLineRange.intersection(clickableRange) {
var rectForLinkPart = layoutManager.boundingRect(forGlyphRange: linkPartIntersection, in: textContainer)
rectForLinkPart.origin.y = rectForLinkPart.origin.y + (textContainer.size.height - textBoundingBox.height) / 2 // Adjust for vertical alignment
rectsForCurrentLink.append(rectForLinkPart)
print("Link rect: \(rectForLinkPart), \(linkPartIntersection)")
}
}
if !rectsForCurrentLink.isEmpty {
linkRects.append(rectsForCurrentLink)
}
}
}
print("linkRects: \(linkRects)")
setNeedsDisplay()
}
}
And I use this as such:
let label = MyLabel()
label.setContentHuggingPriority(.required, for: .vertical)
label.setContentHuggingPriority(.required, for: .horizontal)
view.addSubview(label)
label.snp.makeConstraints { make in
make.width.lessThanOrEqualTo(view.safeAreaLayoutGuide.snp.width).priority(.required)
make.horizontalEdges.greaterThanOrEqualTo(view.safeAreaLayoutGuide).priority(.required)
make.center.equalTo(view.safeAreaLayoutGuide).priority(.required)
}
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .justified
let s = NSMutableAttributedString(string: "Lorem Ipsum: ", attributes: [.font: UIFont.systemFont(ofSize: 17, weight: .regular), .paragraphStyle: paragraphStyle])
s.append(NSAttributedString(string: "This property controls the maximum number of lines to use in order to fit the label's text into its bounding rectangle.", attributes: [.link: URL(string: "https://news.ycombinator.com/") as Any, .foregroundColor: UIColor.link, .font: UIFont.systemFont(ofSize: 14, weight: .regular), .paragraphStyle: paragraphStyle]))
label.attributedText = s
Notice the paragraphStyle.alignment = .justified
This results in:
As you can see, the green rect background is starting a bit further to the right and also ending much further to the right.
If I set the alignment to be .left or .center, then it gives me the correct rects:
Also note that if I keep .justified but change the font size for the "Lorem Ipsom:" part to be a bit different, lets say 16 instead of 17, then it gives me the correct rect too:
Also note that if we remove some word from the string, then also it starts giving correct rect. It seems like if the first line is too squished, then it reports wrong rects.
Why is .justified text alignment giving me wrong rects? How can I fix it?
Topic:
UI Frameworks
SubTopic:
UIKit
I used the Multipeer Connectivity Framework to allow players of my game app to see the highest score along with their own score as the game progresses. It works fine running in 3 or 4 simulators in Xcode. However, I was just told by two Apple support reps that bluetooth connectivity is not allowed between two Apple devices, other than for watches, AirPods, headphones, etc.
My question is: can two iPhones or iPads connect for peer-to-peer play? Can they play offline? If the answer is yes to either or both of those questions, how do I get that to happen since I get an error message when trying to connect two iPhones via bluetooth even though they can see each other in the Other Devices list?
If the answer is no, then why does Apple provide a Multipeer Connectivity Framework and simulate that type of device to device connection with the Xcode simulators?
Topic:
UI Frameworks
SubTopic:
SwiftUI
I am new to the idea of Siri Shortcuts and App Intents. What I want to do is use Siri to run a function in my app.
Such as saying to Siri Zoom in map and that will then call a function in my app where I can zoom in the map. Similarly, I could say Zoom out map and it would call a function to zoom out my map.
I do not need to share any sort of shortcut with the Shortcuts app.
Can someone please point me in the right direction for what type of intents I need to use for this?
Description:
When initiating the print flow via UIPrintInteractionController, and no printer is initially connected, iOS displays all possible paper sizes in the paper selection UI. However, if a printer connects in the background after this view is shown, the list of paper sizes does not automatically refresh to reflect only the options supported by the connected printer.
If the user selects an incompatible paper size (one not supported by the printer that has just connected), the app crashes due to an invalid configuration.
Steps to Reproduce:
Launch the app and navigate to the print functionality.
Tap the Print button to invoke UIPrintInteractionController.
At this point, no printer is yet connected. iOS displays all available paper sizes.
While the paper selection UI is visible, the AirPrint-compatible printer connects in the background.
Without dismissing the controller, the user selects a paper size (e.g., one that is not supported by the printer).
The app crashes.
Expected Result: App should not crash
Once the printer becomes available (connected in the background), the paper size options should refresh automatically.
The list should be filtered to only include sizes that are compatible with the connected printer.
This prevents the user from selecting an invalid option, avoiding crashes.
Actual Result: App crashes
The paper size list remains unfiltered.
The user can still select unsupported paper sizes.
Selecting an incompatible option causes the app to crash, due to a mismatch between UI selection and printer capability.
Topic:
UI Frameworks
SubTopic:
UIKit
When attempting to replicate the tvOS Settings menu layout, where the screen is divided horizontally into two sections, placing a NavigationStack or a Form view on either side of the screen causes focusable views (such as Button, TextField, Toggle, etc.) to be visually clipped when they receive focus and apply the default scaling animation.
Specifically:
If the Form or NavigationStack is placed on the right side, the left edge of the focused view gets clipped.
If placed on the left side, the right edge of the focused view gets clipped.
This issue affects any focusable child view inside the Form or NavigationStack when focus scaling is triggered.
Example code:
struct TVAppMenuMainView: View {
var body: some View {
VStack {
Text("Settings Menu")
.font(.title)
HStack {
VStack {
Text("Left Pane")
}
.frame(width: UIScreen.main.bounds.width * 0.4) // represents only 40% of the screen
.frame(maxHeight: .infinity)
.padding(.bottom)
Divider()
NavigationStack {
Form { // All the buttons will get cut on the left side when each button is focused
Button("First Button"){}
Button("Second Button"){}
Button("Third Button"){}
Button("Forth Button"){}
}
}
}
.frame(maxHeight: .infinity)
.frame(maxWidth: .infinity)
}
.background(.ultraThickMaterial)
}
}
How it looks:
What I have tried:
.clipped modifiers
.ignoresSafeArea
Modifying the size manually
Using just a ScrollView with VStack works as intended, but as soon as NavigationStack or Form are added, the buttons get clipped.
This was tested on the latest 18.5 tvOS BETA
Can the SwiftUI document architecture
Take a file as read-only; never to be written out
Take files too large for memory (multi-MB, or even GB)
I wouldn't want the system to read a gigabyte size file into memory by default. If the system can use a memory-mapped Data as the representation, that'll be something I can make do. It would be even better if I could tell the system that I'll handle all the reading, all I need from it is a reference to the file's location on disk.
Topic:
UI Frameworks
SubTopic:
SwiftUI
I'm trying to use @Query in a wrapper view around a Button to keep a macOS menu command up to date but I keep getting
Set a .modelContext in view's environment to use Query
even though
@Environment(\.modelContext) private var modelContext
is part of the views.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Hi! I'm seeing some weird animation issues building the Food Truck sample application.^1 I'm running from macOS 15.4 and Xcode 16.3. I'm building the Food Truck application for macOS. I'm not focusing on iOS for now.
The FoodTruckModel adds new Order values with an animation:
// FoodTruckModel.swift
withAnimation(.spring(response: 0.4, dampingFraction: 1)) {
self.orders.append(orderGenerator.generateOrder(number: orders.count + 1, date: .now, generator: &generator))
}
This then animates the OrdersTable when new Order values are added.
Here is a small change to OrdersTable:
// OrdersTable.swift
- @State private var sortOrder = [KeyPathComparator(\Order.status, order: .reverse)]
+ @State private var sortOrder = [KeyPathComparator(\Order.creationDate, order: .reverse)]
Running the app now inserts new Order values at the top.
The problem is I seem to be seeing some weird animation issues here. It seems that as soon as the new Order comes in there is some kind of weird glitch where it appears as if part the animation is coming from the side instead of down from the top:
What's then more weird is that if I seem to affect the state of the Table in any way then the next Order comes in with perfect animation.
Scrolling the Table fixes the animation.
Changing the creationData sort order from reverse to forward and back to reverse fixes the animation.
Any ideas? Is there something about how the Food Truck product is built that would cause this to happen? Is this an underlying issue in the SwiftUI infra?
I have a popover/sheet in iOS which allows users to search and add items to a list. When the sheet is shown, the search should always be active.
I am using searchable on a NavigationStack inside the sheet. I am using the isPresented parameter to activate search.
My issue is with the animation of the search activation. Even if I use...
isPresented: .constant(true)
...the search isn't activated until the sheet has completed it's entrance animation, resulting in two stages of animation.
I can't add a video here, but the two images below show the steps I am seeing. First a slide up animation, with the search in the navigation drawer, then a second animation, once the sheet is fully in place, as the search becomes active.
Is it possible to merge these two animations, so search is in place when the sheet animates up?
Topic:
UI Frameworks
SubTopic:
SwiftUI
The pitch slider is not supported on tvOS yet it displays when using the Map() view. Does anyone know how to hide it? It's really getting in the way of my UI.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Hi, I'm working on RealityView and I have two entities in RCP. In order to set views for both entities, I have to create two separate attachments for each entity. What I want to achieve is that when I hover (by eye) on one entity's attachment, it would trigger the hover effect of the other entity's attachment. I try to use the hoverEffectGroup, but it would only activate the hover effect in a subview, instead a complete separate view. I refer to the following WWDC instruction for the hover effect.
https://developer.apple.com/videos/play/wwdc2024/10152/
I have a DocumentGroup working with a FileDocument, and that's fine.
However, when someone creates a new document I want them to have to immediately save it. This is the behavior on ipadOS and iOS from what I can understand (you select where before the file is created).
There seems to be no way to do this on macOS?
I basically want to have someone:
create a new document
enter some basic data
hit "create" which saves the file
then lets the user start editing it
(1), (2), and (4) are done and fairly trivial.
(3) seems impossible, though...?
This really only needs to support macOS but any pointers would be appreciated.
Title: Frequent SIGSEGV crashes in QuartzCore's copy_image (iOS 18.4)
We're experiencing numerous crashes with the following signature:
Exception Codes: fault addr: 0x00000000000000e0
Crashed Thread: 0
Thread 0
0 QuartzCore CA::Render::copy_image(CGImage*, CGColorSpace*, unsigned int, double, double) + 1972
1 QuartzCore CA::Render::copy_image(CGImage*, CGColorSpace*, unsigned int, double, double) + 1260
2 QuartzCore CA::Render::prepare_image(CGImage*, CGColorSpace*, unsigned int, double) + 24
3 QuartzCore CA::Layer::prepare_contents(CALayer*, CA::Transaction*) + 220
4 QuartzCore CA::Layer::prepare_commit(CA::Transaction*) + 284
5 QuartzCore CA::Context::commit_transaction(CA::Transaction*, double, double*) + 488
6 QuartzCore CA::Transaction::commit() + 644
7 UIKitCore ___34-[UIApplication _firstCommitBlock]_block_invoke_2 + 36
8 CoreFoundation ___CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28
9 CoreFoundation ___CFRunLoopDoBlocks + 352
10 CoreFoundation ___CFRunLoopRun + 868
11 CoreFoundation _CFRunLoopRunSpecific + 572
12 GraphicsServices _GSEventRunModal + 168
13 UIKitCore -[UIApplication _run] + 816
14 UIKitCore _UIApplicationMain + 336
15 kugou _main + 132
16 dyld __dyld_process_info_create + 33284
Observations:
1.Crashes consistently occur in Core Animation's image processing pipeline
2.100% of occurrences are on iOS 18.4 devices
3.Crash signature suggests memory access violation during image/copy operations
4.Not tied to any specific device model
Questions for Apple:
1.Is this crash pattern recognized as a known issue in iOS 18.4?
2.Are there specific conditions that could trigger SEGV_ACCERR in CA::Render::copy_image?
3.Could this be related to color space handling or image format requirements changes?
4.Any recommended workarounds while waiting for a system update?
Hi Apple team and community,
We’re encountering a strange issue with Live Activity that seems related to memory management or background lifecycle.
❓ Issue:
Our app updates a Live Activity regularly (every 3 minutes) using .update(...). However, after the app remains in the background for around 8 hours, the Live Activity reverts to the initial state that was passed into .request(...).
Even though the app continues sending updates in the background, the UI on the Lock Screen and Dynamic Island resets to the original state.
How should I program the globe key? If possible, could you teach me in C language?
Topic:
UI Frameworks
SubTopic:
General
In SwiftUI I want to create a list with LazyVstack and each row item in the LazyVstack is a LazyHstack of horizontally scrollable list of images with some description with line limit of 3 and width of every item is fixed to 100 but height of every item is variable as per description text content.
But in any of the rows if the first item has image description of 1 line and the remaining items in the same row has image description of 3 lines then the LazyHStack is truncating all the image descriptions in the same row to one line making all the items in that row of same height.
Why LazyHStack is not supporting items of varying height ?
Expected behaviour should be that height of every LazyHStack should automatically adjust as per item content height. But it seems SwiftUI is not supporting LazyHstack with items of varying height.
Will SwiftUI ever support this feature?
Topic:
UI Frameworks
SubTopic:
SwiftUI
I have a view with some buttons, and add 2 gestures using simultaneously. My app works well when built with XCode less than 16, or run on iOS less than 18.0.
Example code is below:
VStack(spacing: 0) {
Button {
print("button tapped")
} label: {
Rectangle()
.foregroundColor(.red)
}
.frame(height: 100)
}
.gesture(
DragGesture(minimumDistance: 0)
.onEnded { value in
print("single tap")
}
.simultaneously(with:
TapGesture(count: 2).onEnded {
print("double tap")
}
)
)
.frame(width: 200, height: 200)
.border(Color.purple)
I expect the action on Button should be recognized and print out button tapped, but only single tap and double tap are recognized
Is there a way to detect when your apps (or any app I guess) is being moved by the user clicking and dragging the main window around the desktop at all?
I'm trying to find out if there's a way I can find out if a window is being clicked and dragged and whether there's certain triggers to the movement a little bit like shaking an iPhone with Shake to Undo.
Thanks
Hello.
I use NavigationStack for navigating in app. I have 4 screens - A, B, C, D. In some moment I have path [A, B, C] for NavigationStack. After user did action I should show path [A, B, D]. In other hands I should replace screen C with screen D.
struct HomeView: View {
@ObservedObject var viewModel: HomeViewModel
var body: some View {
NavigationStack(path: $viewModel.path) {
ContentView()
.navigationDestination(for: HomeViewModel.Path.self) { destination in
// B, C, D views here...
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
Solution looks like same as for UIKit. I replaced last item in stack. It works, but "push" animation broke.
var updatedPath = self.path
updatedPath.removeLast()
updatedPath.append(newPathItem)
self.path = updatedPath
I found suggest in Internet that you can remove view from stack after some delay. But it has some magic. For example 1 second delay works properly on iOS 18, but cause crash on iOS 16. 1 millisecond delay works on iOS 16, but sometimes didn't.
self.path.append(newPathItem)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1000)) {
UIView.setAnimationsEnabled(false)
self.path.remove(at: self.path.count - 2)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1)) {
UIView.setAnimationsEnabled(true)
}
}
It is easy task to replace current top screen in UINavigationController of UIKit. How I can do it properly in SwiftUI and save animation?