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

MTKView delegate ownership during view controller transitions
The Problem When transitioning between view controllers that each have their own MTKView but share a Metal renderer backend, we run into delegate ownership conflicts. Only one MTKView can successfully render at a time, since setting the delegate on one view requires removing it from the other, leading to paused views during transitions. For my app, I need to display the same visuals across multiple views and have them all render correctly. Current Implementation Approach I've created a container object that manages the MTKView and its relationship with the shared renderer: class RenderContainer { let metalView: MTKView private let renderer: MetalRenderer func startRendering() { metalView.delegate = renderer metalView.isPaused = false } func stopRendering() { metalView.isPaused = true metalView.delegate = nil } } View controllers manage the rendering lifecycle in their view appearance methods: override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) renderContainer.startRendering() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) renderContainer.stopRendering() } Observations & Issues During view controller transitions, one MTKView must stop rendering before the other can start. Also there is no guarantee that the old view will stop rendering before the new one starts, with the current API design. This creates a visual "pop" during animated transitions Setting isPaused = true helps prevent unnecessary render calls but doesn't solve the core delegate ownership problem The shared renderer maintains its state but can only output to one view at a time Questions What's the recommended approach for handling MTKView delegate ownership during animated transitions? Are there ways to maintain visual continuity without complex view hierarchies? Should I consider alternative architectures for sharing the Metal content between views? Any insights for this scenario would be appreciated.
0
0
66
2d
XCUITest snapshot dictionary represenation giving wrong coordinates
Problem I am developing a WebDriver agent for automation and using dictionaryRepresentation to retrieve the coordinates of the iOS app hierarchy. However, I am encountering an issue with the accuracy of the x and y coordinates. Approach Tried I tested the setup on: iPhone 12 Pro Max (iOS 16.2): Accuracy issues with the coordinates were observed. iPhone SE (3rd Generation) (iOS 16.2): Coordinates were accurate for tap actions, with no issues identified. Observation It appears that devices with fingerprint biometric authentication provide accurate coordinates. Can anyone help here to understand is there anything wrong in the code. Are do we have to adjust frame of the element for different devices? Sample Code - (NSDictionary *)json_tree { NSDictionary<XCUIElementAttributeName, id> *dictionaryRepresentation = [[self snapshotWithError:nil] dictionaryRepresentation]; return [self.class dictionaryForElementAttributes:dictionaryRepresentation recursive:YES]; } // This method converts the dictionary to CGRect, handling any broken frame values (e.g., Infinity) + (CGRect)handleBrokenFrameFromDict:(id)frameDict { if ([frameDict isKindOfClass:[NSDictionary class]]) { CGFloat originX = [frameDict[@"X"] floatValue]; CGFloat originY = [frameDict[@"Y"] floatValue]; CGFloat sizeWidth = [frameDict[@"Width"] floatValue]; CGFloat sizeHeight = [frameDict[@"Height"] floatValue]; CGRect frame = CGRectMake(originX, originY, sizeWidth, sizeHeight); // Replace Infinity values with CGRectZero return (isinf(frame.size.width) || isinf(frame.size.height) || isinf(frame.origin.x) || isinf(frame.origin.y)) ? CGRectZero // or another predefined constant like BROKEN_RECT : CGRectIntegral(frame); } return CGRectZero; // If frameDict is not a valid dictionary, return CGRectZero } // This method converts CGRect into a dictionary representation for "rect" + (NSDictionary *)rectDictionaryFromCGRect:(CGRect)rect { return @{ @"x": @(rect.origin.x), @"y": @(rect.origin.y), @"width": @(rect.size.width), @"height": @(rect.size.height) }; } + (NSString *)label:(NSDictionary<XCUIElementAttributeName, id> *)dict { XCUIElementType elementType = [dict[XCUIElementAttributeNameElementType] intValue]; NSString *label = dict[XCUIElementAttributeNameLabel]; if (elementType == XCUIElementTypeTextField || elementType == XCUIElementTypeSecureTextField) { return label; } return FBTransferEmptyStringToNil(label); } + (NSString *)name:(NSDictionary<XCUIElementAttributeName, id> *)dict { NSString *identifier = dict[XCUIElementAttributeNameIdentifier]; if (nil != identifier && identifier.length != 0) { return identifier; } NSString *label = dict[XCUIElementAttributeNameLabel]; return FBTransferEmptyStringToNil(label); } + (NSString *)value:(NSDictionary<XCUIElementAttributeName, id> *)dict { id value = dict[XCUIElementAttributeNameValue]; XCUIElementType elementType = [dict[XCUIElementAttributeNameElementType] intValue]; if (elementType == XCUIElementTypeStaticText) { NSString *label = [self label:dict]; value = FBFirstNonEmptyValue(value, label); } else if (elementType == XCUIElementTypeButton) { NSNumber *isSelected = [dict[XCUIElementAttributeNameSelected] boolValue] ? @YES : nil; value = FBFirstNonEmptyValue(value, isSelected); } else if (elementType == XCUIElementTypeSwitch) { value = @([value boolValue]); } else if (elementType == XCUIElementTypeTextView || elementType == XCUIElementTypeTextField || elementType == XCUIElementTypeSecureTextField) { NSString *placeholderValue = dict[XCUIElementAttributeNamePlaceholderValue]; value = FBFirstNonEmptyValue(value, placeholderValue); } value = FBTransferEmptyStringToNil(value); if (value) { value = [NSString stringWithFormat:@"%@", value]; } return value; } + (NSDictionary *)dictionaryForElementAttributes:(NSDictionary<XCUIElementAttributeName, id> *)dict recursive:(BOOL)recursive { NSMutableDictionary *info = [[NSMutableDictionary alloc] init]; info[@"type"] = [FBElementTypeTransformer shortStringWithElementType:[dict[XCUIElementAttributeNameElementType] intValue]]; info[@"rawIdentifier"] = FBValueOrNull([dict[XCUIElementAttributeNameIdentifier] isEqual:@""] ? nil : dict[XCUIElementAttributeNameIdentifier]); info[@"name"] = FBValueOrNull([self name:dict]); info[@"value"] = FBValueOrNull([self value:dict]); info[@"label"] = FBValueOrNull([self label:dict]); // Handle the frame value CGRect frame = [self handleBrokenFrameFromDict:dict[XCUIElementAttributeNameFrame]]; info[@"frame"] = NSStringFromCGRect(frame); // Add the rect value info[@"rect"] = [self rectDictionaryFromCGRect:frame]; info[@"isEnabled"] = [@([dict[XCUIElementAttributeNameEnabled] boolValue]) stringValue]; // visible // accessible info[@"isFocused"] = [@([dict[XCUIElementAttributeNameHasFocus] boolValue]) stringValue]; if (!recursive) { return info.copy; } NSArray<NSDictionary<XCUIElementAttributeName, id> *> *childElements = [dict[XCUIElementAttributeNameChildren] isKindOfClass:[NSArray class]] ? dict[XCUIElementAttributeNameChildren] : @[]; if ([childElements count]) { info[@"children"] = [[NSMutableArray alloc] init]; for (NSDictionary<XCUIElementAttributeName, id> * childSnapshot in childElements) { [info[@"children"] addObject:[self dictionaryForElementAttributes:childSnapshot recursive:YES]]; } } return info; }
1
0
62
2d
How to drag and drop an image file to find in an app
import Cocoa @available(macOS 10.13, *) let imagePboardType = NSPasteboard.PasteboardType.fileURL class DragSourceView: NSImageView { weak var dragSourceDelegate: NSDraggingSource? override func mouseDown(with event: NSEvent) { //拖放数据定义 let pasteboardItem = NSPasteboardItem() //设置数据的Provider if #available(macOS 10.13, *) { pasteboardItem.setDataProvider(self, forTypes: [NSPasteboard.PasteboardType.fileURL]) } else { // Fallback on earlier versions } //拖放item let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem) draggingItem.draggingFrame = NSRect(x: 100 , y: 10, width: 100, height: 100) //拖放可视化图象设置 draggingItem.imageComponentsProvider = { let component = NSDraggingImageComponent(key: NSDraggingItem.ImageComponentKey.icon) component.frame = NSRect(x: 0, y: 0, width: 16, height: 16) component.contents = NSImage(size: NSSize(width: 32,height: 32), flipped: false, drawingHandler: { [unowned self] rect in { self.image?.draw(in: rect) return true }() } ) return [component] } //开始启动拖放sesson self.beginDraggingSession(with: [draggingItem], event: event, source: self.dragSourceDelegate!) } } extension DragSourceView: NSPasteboardItemDataProvider { func pasteboard(_ pasteboard: NSPasteboard?, item: NSPasteboardItem, provideDataForType type: NSPasteboard.PasteboardType) { // let data = self.image?.tiffRepresentation let data = "/Users/slowdony/Desktop/640.jpeg" let dataUrl = data.data(using: String.Encoding(rawValue: NSUTF8StringEncoding))! item.setData(dataUrl, forType: type) } } import Cocoa class ViewController: NSViewController { @IBOutlet weak var sourceView: DragSourceView! override func viewDidLoad() { super.viewDidLoad() self.sourceView.dragSourceDelegate = self } } extension ViewController: NSDraggingSource { //返回拖放操作类型 func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor context: NSDraggingContext) -&gt; NSDragOperation { if (context == .outsideApplication){ return .copy } else{ return .generic } } //开始拖放代理回调 func draggingSession(_ session: NSDraggingSession, willBeginAt screenPoint: NSPoint) { print("draggingSession beginAt \(screenPoint)") } //拖放鼠标移动时的代理回调 func draggingSession(_ session: NSDraggingSession, movedTo screenPoint: NSPoint) { print("draggingSession movedTo \(screenPoint)") } //结束拖放代理回调 func draggingSession(_ session: NSDraggingSession, endedAt screenPoint: NSPoint, operation: NSDragOperation) { print("draggingSession endedAt \(screenPoint)") } } I am dragging an image to the desktop through the above code, failed, help
2
0
51
2d
What's the best way to support Genmoji with SwiftUI?
I want to support Genmoji input in my SwiftUI TextField or TextEditor, but looking around, it seems there's no SwiftUI only way to do it? If none, it's kind of disappointing that they're saying SwiftUI is the path forward, but not updating it with support for new technologies. Going back, does this mean we can only support Genmoji through UITextField and UIViewRepresentable? or there more direct options? Btw, I'm also using SwiftData for storage.
0
0
95
2d
NSToolbarItemGroup dynamically update subitems in toolbar
Developing on Monterey 12.7.5 I'm having trouble with updating subitems on NSToolbarItemGroup when selecting the item directly from the NSToolbar items array. I select the group item off the items array on the toolbar, and then call setSubitems: on the item, with a new array of NSToolbarItems. The group item disappears from the toolbar. It seems to leave a blank invisible item in the toolbar taking up space. I can't manually reinsert the item into the toolbar until I drag out the blank item, then drag back in the real item. Once dragged back in from the palette it displays correctly. The workaround I've come up with is to remove the item with NSToolbar removeItemAtIndex: and reinsert it with NSToollbar insertItemWithItemIdentifier:atIndex:. This works to update the subitems. Every other toolbar item property that I've tried has been able to update the item directly in the toolbar. It's only the group item's subitems that don't want to update correctly. Is there a correct way to do this that I'm missing? Calling [toolbar validateVisibleItems] didn't seem to help.
0
0
70
2d
SwiftData: Default value for added property
Let's say I have a model like this: @Model final class DataModel { var firstProperty: String = "" } Later on I create a new property as such: @Model final class DataModel { enum DataEnum { case dataCase } var firstProperty: String = "" var secondProperty: DataEnum? = .dataCase } My expectation is for the data that is already stored, the secondProperty would be added with a default value of .dataCase. However, it's being set to nil instead. I could have sworn it would set to the default value given to it. Has that changed, or has it always been this way? Does this require a migration plan?
0
0
92
2d
Prevent macOS window.level floating from showing on all screens in a multi monitor setup?
I am using the window.level set to .floating as described here: https://developer.apple.com/documentation/appkit/nswindow/level The setting itself works okay. However, in a multi monitor setup, the floating window is appearing on both the screens. How can I prevent this? My users report that before macOS Sonoma, this used to not happen. Has this behaviour changed? How can I revert back to the old behaviour?
1
0
83
3d
SwiftUI DatePicker size not configurable
Hey guys, I'm totally new to Swift programming and I'm setting up a view for registering users. I use a VStack to organize the TextFields as well as a DatePicker, but the last one seems to be very rebellious. Here's my code: VStack { TextField("E-Mailadresse", text: $mail) .frame(height: 30) .textFieldStyle(.roundedBorder) .multilineTextAlignment(.center) .focused($hasFocus, equals: .mail) .onKeyPress(.tab, action: {hasFocus = .password; return .handled}) SecureField("Passwort", text: $password) .frame(height: 30) .textFieldStyle(.roundedBorder) .multilineTextAlignment(.center) .focused($hasFocus, equals: .password) .onKeyPress(.tab, action: {hasFocus = .name; return .handled}) TextField("Name", text: $name) .frame(height: 30) .textFieldStyle(.roundedBorder) .multilineTextAlignment(.center) .focused($hasFocus, equals: .name) .onKeyPress(.tab, action: {hasFocus = .prename; return .handled}) TextField("Vorname", text: $prename) .frame(height: 30) .textFieldStyle(.roundedBorder) .multilineTextAlignment(.center) .focused($hasFocus, equals: .prename) .onKeyPress(.tab, action: {hasFocus = .birthday; return .handled}) DatePicker("Geb.:", selection: $birthday, displayedComponents: [.date]) .datePickerStyle(.wheel) .clipped() //.focused($hasFocus, equals: .birthday) Button("Registrieren") {self.register()} .padding(.top, 20) .keyboardShortcut(.defaultAction) } .frame(width: 375) } And this is how it looks like: As you can see, neither is the DatePicker centered correctly (it's more left located) nor is it clipped (reduced). I also tried adding a .frame() to itself, then I was ably to reduce it to the preferred height, but I can' reduce its width and as a result of this, I can also not write a full label like "Date of Birth" or something, because the wheel of the DatePicker always overlays it... Is that a kind of misbehavior or am I missing something? Thank you very much in anticipation for your feedback! Kind regards Kevin
1
0
98
3d
Management of multiple root views in SwiftUI
Hey guys, I'm totally unexperienced in Swift coding and I'm doing my first steps using Swift Playgrounds on my macOS as well as on my iPadOS. I'm setting up a simple App that can be divided in 4 main categories (Splash, Authentication, Content, Setup). Each category (except the Splash as the short intro when running the app) can have a NavigationStack (e. g. switching between login view, register view, forgott password view in authentication). So I thought about having a root view for each of them. My google research gave me lots of ways and hints but it's not clear at all for me if I should and how I should do this. I often read about a RootViewController but I guess that's UIKit stuff and nothing for SwiftUI. Then I read about delegates and such. Then, I read an article that exactly fits my goals and I just liked to get your opinion what you think about this way to solve my plan: First of all, I define a separate class for a appRootManager: final class appRootManager: ObservableObject { enum eRootViews { case Splash, Authentification, Content, Setup } @Published var currentRoot: eRootViews = .Splash } The main app file looks like this: @main struct MyApp: App { @StateObject private var oRootManager = appRootManager() var body: some Scene { WindowGroup() { Group { switch oRootManager.currentRoot { case .Splash: viewSplash() case .Authentification: viewLogin() case .Content: viewContent() case .Setup: viewSetup() } } .environmentObject(oRootManager) .modelContainer(for: [Account.self]) } } } In each of the for root view files (e. g. Splash view) I make the appRootManager addressable and switch the root view by updating the enum value, like for example: struct viewSplash: View { @EnvironmentObject private var oRootManager: appRootManager var body: some View { ZStack { Color.blue .ignoresSafeArea() Text("Hello World") .font(.title) .fontWeight(.semibold) .foregroundColor(.white) } .onAppear() { DispatchQueue.main.asyncAfter(deadline: .now() + 3) { withAnimation(.spring()) {oRootManager.currentRoot = .Authentification} } } } } It works fine and does exactly what I like to have (when I run the app out of Swift Playgrounds). I'm just wondering why it does not work in the App Preview in Swift Playgrounds and this is why I'd like to have your opinion to the way I solve my plan. I'm very happy for any feedback. Thanks a lot in anticipation! Kind regards Kevin
2
0
99
3d
Bring iOS app to foreground from Apple Watch app
Exploring Live Activity feature for Apple Watch right now and found that it has this default view with "Open on iPhone" button when you tap Live Activity. That button perfectly brings iOS app to foreground as if you tapped iOS's Live Activity. Is there a way to mimic that behavior from inside Watch app code? From inside WKApplicationDelegate, for example Tried openSystemURL but it seems lile it's only available for tel or sms links
1
0
89
3d
Limiting UITableView Width Across Different Table View Configurations
I have an iOS App which looks great on iPhone, portrait only, which makes a lot of use of UITableViews. On iPad those tables look stretched out in Landscape. On MacOS with Apple Silicon the app can be resized to any size and the table views look very stretched. There are views in the App which users want to resize so limiting app size not an option. I've been modifying the app's table views to limit their width and centre them using constraints. This isn't easy, it's a lot of work as UITableViewController doesn't allow for constraining the table width. Or does it? So I've changed them to UIViewControllers with UITableView imbedded in the root UIView with constraints. Looks really nice. Now I've just run into the limitation that static tables, which I have a number of, aren't allowed to be embedded. So how can I limit the width of them? I really don't want to add a lot of dynamic code. Please tell me there's an simpler, more elegant method to what really makes a much more aesthetically pleasing UI on iOS App running on iPad and MacOS? TIA!
2
0
84
3d
Problem with audio files in Swift
Hi guys, I've been this app for quite a while and I wanted to add audio to it but I've encountered a strange bug. Whenever I try to play the audio from the testing device, it prints out that the audio file cannot be found. I've checked multiple times the names and the code and I get no errors there whatsoever. I have no idea what might be causing this. Here's a part of the code: `import SwiftUI import AVFoundation struct Card: Identifiable { let id = UUID() let heading: String let description: String let imageName: String let detailDescription: String let sonification: String } struct ExplorepageUI: View { @State private var selectedCard: Card? @State private var showMore = false @State private var currentIndex = 0 @State private var currentCards: [Card] = [] let galaxies = [ Card(heading: "The Mice Galaxies", description: "They’re located about 300 million light-years away in the constellation Coma Berenices.", imageName: "TheMiceGalaxiesHubble", detailDescription:""" Their name refers to the long tails produced by tidal action, the relative difference between gravitational pulls on the near and far parts of each galaxy, known here as a galactic tide. It is a possibility that both galaxies, which are members of the Coma Cluster, have experienced collision, and will continue colliding until they coalesce. The colors of the galaxies are peculiar. In NGC 4676A a core with some dark markings is surrounded by a bluish white remnant of spiral arms. The tail is unusual, starting out blue and terminating in a more yellowish color, despite the fact that the beginning of each arm in virtually every spiral galaxy starts yellow and terminates in a bluish color. NGC 4676B has a yellowish core and two arcs; arm remnants underneath are bluish as well. The galaxies were photographed in 2002 by the Hubble Space Telescope. In the background of the Mice Galaxies, there are over 3000 galaxies, at distances up to 13 billion light-years. """, sonification: "SonificationoftheMiceGalaxies"), `class MusicPlayer: ObservableObject { private var audioPlayer: AVPlayer? func playSound(named sonificationFileName: String){ if let url = Bundle.main.url(forResource: sonificationFileName, withExtension: "mp3"){ print("✅ Found audio file at: \(url)") audioPlayer = try? AVPlayer(url: url) audioPlayer?.play() print("🎵 Audio should now be playing!") } else { print("❌ Audio file not found: \(sonificationFileName).mp3") } } func pause(){ audioPlayer?.pause() } }
1
0
106
4d
onMove bug
I'm not sure where to report this, so here it is. If you have a list of items and you make them clickable and movable, moving one or more items in the list and then clicking will cause them to move. This is yet another reason that SwiftData needs to track onMove. Minimal reproducible code: // // ContentView.swift // exampleBug // // Create a new project. // Replace the default Item class with the one below, and replace ContentView with its class below // Run the app and add a few items a few seconds apart so you can tell them apart. // Drag an item to a new position in the list. // Click one of the checkboxes and watch the list positions change for no reason! // import SwiftUI import SwiftData @Model final class Item { var timestamp: Date var checkbox: Bool = false init(timestamp: Date) { self.timestamp = timestamp } } struct ContentView: View { @Environment(\.modelContext) private var modelContext @State private var editMode = EditMode.inactive @Query private var items: [Item] var body: some View { NavigationStack { List { ForEach(items) { item in HStack { Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) Button("", systemImage: item.checkbox ? "checkmark.circle.fill" : "circle") { item.checkbox.toggle() try? modelContext.save() } } } .onMove(perform: { indices, newOffset in var theItems = items theItems.move(fromOffsets: indices, toOffset: newOffset) }) } .environment(\.editMode, $editMode) .moveDisabled(false) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } } func addItem() { withAnimation { let newItem = Item(timestamp: Date()) modelContext.insert(newItem) } } func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(items[index]) } } } } #Preview { ContentView() .modelContainer(for: Item.self, inMemory: true) } code-block
2
0
116
4d
I can't stand IOS 18 photos app
I made an account on this site for the sole reason to post this. I can not stand the IOS 18 photo app, to put it bluntly its sucks, it's made the app unusable. I was nice, I'd thought I'd give it a month or two but no, it still sucks. I wish I could uninstall IOS 18 solely cause of it. I hate the UI, its utterly unintuitive.
1
0
118
4d
SwiftUI TextSelection crash on macOS
I have a very simple SwiftUI app, works fine on iOS, crashes on macOS: struct ContentView: View { @State var testStr: String = "" @State var selection: TextSelection? = nil var body: some View { VStack { TextField("Test", text: $testStr, selection: $selection) .onChange(of: selection) {print("selection changed")} } .padding() } } • Start app, write something in the TextField and move the cursor around. iOS: "selection changed" Mac: nothing (Bug ?) • double click on some word both Mac and iOS: "selection changed" • write some more in the TextField iOS: selection changed Mac: crash Any idea what I am doing wrong? Gerriet.
2
0
117
4d
TipViewStyle not compiling
I'm creating a simple TipViewStyle based on sample code but it fails to compile. It displays: Type 'MyViewStyle' does not conform to protocol 'TipViewStyle' When I choose the Fix option, it adds this line: `type alias Body = type' What should the type be here? struct MyTipViewStyle: TipViewStyle { func makeBody(config: Configuration) -> some View { VStack { config.title config.message? } }
2
0
135
4d