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
Posts under UI Frameworks topic

Post

Replies

Boosts

Views

Created

SwiftUI menu not resizing images
I failed to resize the icon image from instances of NSRunningApplication. I can only get 32×32 while I'm expecting 16×16. I felt it unintuitive in first minutes… Then I figured out that macOS menu seems not allowing many UI customizations (for stability?), especially in SwiftUI. What would be my best solution in SwiftUI? Must I write some boilerplate SwiftUI-AppKit bridging?
1
0
78
2w
does ios26 really prevent toolbars and child views from functioning?
I'm building an app with a min iOS of 26. In iOS 26, bottom toolbars are attached to the NavStack where in ios18 they were attached to a vstack or scrollview. But in ios26 if the toolbar is attached to something like a vstack, it displays too low on an iPhone 16e and sits behind the tab bar. Fine. But with a parent-child view, the parent has a NavStack (with bottom toolbar attached) and the child view doesn't have a NavStack. So...that's a problem. The functional impact of this contradiction (bottom toolbars go on the NavStack and child views don't have a NavStack) is actually two problems. the parent view bottom toolbar shows up on the child view (because it's the closest NavStack) whether it's appropriate on the view or not. the child view can't have a viable bottom toolbar because without a NavStack any buttons are hidden behind the tab view. The second problem can be worked around using a top toolbar or safe area edge inset instead of a toolbar at the bottom or something. But those don't solve the first problem of the parent view bleeding through. So, I have to be crazy, right. Apple wouldn't create a scenario where bottom toolbars are not functional on parent-child views in ios26. Any suggestions that I'm missing?
Topic: UI Frameworks SubTopic: SwiftUI
0
0
57
2w
WWDC21 Demystify SwiftUI question
When the guy was talking about structural identity, starting at about 8:53, he mentioned how the swiftui needs to guarantee that the two views can't swap places, and it does this by looking at the views type structure. It guarantees that the true view will always be an A, and the false view will always be a B. Not sure exactly what he means because views can't "swap places" like dogs. Why isn't just knowing that some View is shown in true, and another is shown in false, enough for its identity? e.g. The identity could be "The view on true" vs "The view on false", same as his example with "The dog on the left" vs "The dog on the right"
0
0
58
2w
How to animate `UIHostingController.view` frame when my View's size changes?
I have a UIHostingController on which I have set: hostingController.sizingOptions = [.intrinsicContentSize] The size of my SwiftUI content changes with animation (I update a @Published property on an ObservableObject inside a withAnimation block). However, I notice that my hostingController.view just jumps to the new frame without animating the change. Question: how can I animate the frame changes in UIHostingController that are caused by sizingOptions = [.intrinsicContentSize]
3
1
190
2w
UIKit: readableContentGuide is too wide on iPads iOS 26.x
We noticed in multiple apps that readableContentGuide is way too wide on iOS 26.x. Here are changes between iPad 13inch iOS 18.3 and the same device iOS 26.2 (but this affects also iOS 26.0 and iOS 26.1): 13 inch iOS 18 Landscape ContentSizeCategory: XS, Width: 1376.0 , Readable Width: 560.0 S, Width: 1376.0 , Readable Width: 600.0 M, Width: 1376.0 , Readable Width: 632.0 L, Width: 1376.0 , Readable Width: 664.0 XL, Width: 1376.0 , Readable Width: 744.0 XXL, Width: 1376.0 , Readable Width: 816.0 XXXL,Width: 1376.0 , Readable Width: 896.0 A_M, Width: 1376.0 , Readable Width: 1096.0 A_L, Width: 1376.0 , Readable Width: 1280.0 A_XL,Width: 1376.0 , Readable Width: 1336.0 13 inch iOS 26 Landscape ContentSizeCategory: XS, Width: 1376.0 , Readable Width: 752.0 S, Width: 1376.0 , Readable Width: 800.0 M, Width: 1376.0 , Readable Width: 848.0 L, Width: 1376.0 , Readable Width: 896.0 XL, Width: 1376.0 , Readable Width: 1000.0 XXL, Width: 1376.0 , Readable Width: 1096.0 XXXL,Width: 1376.0 , Readable Width: 1200.0 A_M, Width: 1376.0 , Readable Width: 1336.0 The code I used: class ViewController: UIViewController { lazy var readableView: UIView = { let view = UIView() view.backgroundColor = .systemBlue view.translatesAutoresizingMaskIntoConstraints = false return view }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(readableView) NSLayoutConstraint.activate([ readableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), readableView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor), readableView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor), readableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if readableView.frame.width > 0 { let orientation = UIDevice.current.orientation print(""" ContentSizeCategory: \(preferredContentSizeCategoryAsString()) Width: \(view.frame.width) , Readable Width: \(readableView.frame.width), Ratio: \(String(format: "%.1f", (readableView.frame.width / view.frame.width) * 100))% """) } } func preferredContentSizeCategoryAsString() -> String { switch UIApplication.shared.preferredContentSizeCategory { case UIContentSizeCategory.accessibilityExtraExtraExtraLarge: return "A_XXXL" case UIContentSizeCategory.accessibilityExtraExtraLarge: return "A_XXL" case UIContentSizeCategory.accessibilityExtraLarge: return "A_XL" case UIContentSizeCategory.accessibilityLarge: return "A_L" case UIContentSizeCategory.accessibilityMedium: return "A_M" case UIContentSizeCategory.extraExtraExtraLarge: return "XXXL" case UIContentSizeCategory.extraExtraLarge: return "XXL" case UIContentSizeCategory.extraLarge: return "XL" case UIContentSizeCategory.large: return "L" case UIContentSizeCategory.medium: return "M" case UIContentSizeCategory.small: return "S" case UIContentSizeCategory.extraSmall: return "XS" case UIContentSizeCategory.unspecified: return "U" default: return "D" } } } Please advise, it feels completely broken. Thank you.
1
1
121
2w
Text with .secondary vanishes when Material background is clipped to UnevenRoundedRectangle in ScrollView
I just found a weird bug: If you place a Text view using .foregroundStyle(.secondary), .tertiary, or other semantic colors inside a ScrollView, and apply a Material background clipped to an UnevenRoundedRectangle, the text becomes invisible. This issue does not occur when: The text uses .primary or explicit colors (e.g., .red, Color.blue), or The background is clipped to a standard shape (e.g., RoundedRectangle). A minimal reproducible example is shown below: ScrollView{ VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello World.") .font(.system(size: 15)) .foregroundStyle(.quinary) } } .padding() .frame(height: 100) .background(Material.regular) .clipShape(UnevenRoundedRectangle(topLeadingRadius: 10,bottomLeadingRadius: 8,bottomTrailingRadius:8, topTrailingRadius: 8))
0
0
130
2w
SwiftUI TextEditor: replaced text jumps outside current selection
I have a text editor where I replace the selected text when a button is tapped. Most of the time it works, but sometimes the new text is inserted at the end of the text instead of at the selected position. Is this a bug? @Bindable var note: Richnote @State private var selection = AttributedTextSelection() var body: some View { VStack { TextEditor(text: $note.content, selection: $selection) Button("Replace text") { let textToInsert = "A long text that makes me think lalala" note.content.replaceSelection(&selection, withCharacters: textToInsert) }
Topic: UI Frameworks SubTopic: SwiftUI
2
0
65
2w
Why MapKit Is So Unpredictable for macOS?
I have an existing iOS app with MapKit. It always shows the current user location with UserAnnotation. But the same isn't true for macOS. I have this sample macOS application in SwiftUI. In the following, the current user location with a large blue dot appears only occasionally. It won't, 19 of 20 times. Why is that? I do have a location privacy key in Info.plist. And the Location checkbox is on under Signing & Capabilities. import SwiftUI import MapKit struct ContentView: View { @State private var markerItems: [MarkerItem] = [ MarkerItem(name: "Farmers Market 1", lat: 35.681, lon: 139.691), MarkerItem(name: "Farmers Market 2", lat: 35.685, lon: 139.695), MarkerItem(name: "Farmers Market 3", lat: 35.689, lon: 139.699) ] @State private var position: MapCameraPosition = .automatic var body: some View { Map(position: $position) { UserAnnotation() ForEach(markerItems, id: \.self) { item in Marker(item.name, coordinate: CLLocationCoordinate2D(latitude: item.lat, longitude: item.lon)) } } .mapControlVisibility(.hidden) .mapStyle(.standard(elevation: .realistic)) .ignoresSafeArea() } } #Preview { ContentView() } struct MarkerItem: Hashable { let name: String let lat: Double let lon: Double }
0
0
32
3w
Tabview page dots like in the weather app
Hi, I am looking to display (in SwiftUI) the Tabview page dots like in the weather app in the toolbar, an important thing is I want to keep page controls by tapping and scrubbing. Actually, I want to do what's on Apple Design's Page Controls page; here's the link and a photo of what I'd like to do. Could you help me? https://developer.apple.com/design/human-interface-guidelines/page-controls
1
0
67
3w
How to implement bullet and numbered list functionality in ios26 attributed string text editor
I'm looking to support toggleable bullet and numbered lists in my IOS 26 app. currently my text editor looks like this @Binding var text: AttributedString var requestFocus: Bool = false @State private var selection = AttributedTextSelection() @FocusState private var isFocused: Bool var body: some View { TextEditor(text: $text, selection: $selection) .scrollContentBackground(.hidden) .background(Color.clear) .focused($isFocused) .safeAreaInset(edge: .bottom) { if isFocused { FormattingToolbar(text: $text, selection: $selection) .padding(.horizontal) .padding(.vertical, 8) .background(Color(UIColor.systemBackground)) } } .onChange(of: requestFocus) { _, newValue in if newValue { isFocused = true } } } } i cant find any useful docs on how to best implement this. anything helps, thanks
Topic: UI Frameworks SubTopic: SwiftUI
3
0
160
3w
AppKit - Legal to Change a View's Frame in -viewDidLayout?
I have (had) a view controller that does a bit of manual layout in a -viewDidLayout override. This was pretty easy to manage - however since introducing NSGlassEffectView into the view hierarchy I sometimes am getting hit with "Unable to simultaneously satisfy constraints" and Appkit would break a constraint to 'recover.' It appears translatesAutoresizingMaskIntoConstraints is creating some really weird fixed width and height constraints. Here I wasn't doing any autolayout - just add the glass view and set its frame in -viewDidLayout. At runtime since I do manual layout in -viewDidLayout the frames are fixed and there is no real "error" in my app in practice though I wanted to get rid of the constraint breaking warning being logged because I know Autolayout can be aggressive about 'correctness' who knows if they decide to throw and not catch in the future. In my perfect world I would probably just prefer a view.doesManualLayout = YES here - the subviews are big containers no labels so localization is not an issue for me. Rather than playing with autoresizing masks to get better translated constraints I decided to set translatesAutoresizingMaskIntoConstraints to NO and make the constraints myself. Now I get hit with the following exception: "The window has been marked as needing another Layout Window pass, but it has already had more Layout Window passes than there are views in the window" So this happens because the view which now has constraints -- I adjusted the frame of it one point in -viewDidLayout. My question is - is not legal to make changes in -viewDidLayout - which seems like the AppKit version of -viewDidLayoutSubviews. In UIKit I always thought it was fine to make changes in -viewDidLayoutSubviews to frames - even if constraints were used - this is a place where you could override things in complex layouts that cannot be easily described in constraints. But in AppKit if you touch certain frames in -viewDidLayout it can now cause this exception (also related: https://developer.apple.com/forums/thread/806471) I will change the constant of one of the constraints to account for the 1 point adjustment but my question still stands - is it not legal to touch frames in -viewDidLayout when autolayout constraints are used on that subview? It is (or at least was if I remember correctly) permitted to change the layout in -viewDidLayoutSubviews in UIKit but AppKit seems to be more aggressive in its checking for layout correctness). What about calling -sizeToFit on a control in viewDidLayout or some method that has side effect of invalidating layout in a non obvious way, is doing things like this now 'dangerous?' Shouldn't AppKit just block the layout from being invalidated from within -viewDidLayout - and leave whatever the layout is as is when viewDidLayout returns (thus making -viewDidLayout a useful place to override layout in the rare cases where you need a sledgehammer?)
2
0
219
3w
tabViewBottomAccessory causes unstable view identity for views accessing Environment or State
Views placed inside tabViewBottomAccessory that access @Environment values or contain @State properties experience unstable identity, as shown by Self._printChanges(). The identity changes on every structural update to the TabView, even though the view's actual identity should remain stable. This causes unnecessary view recreation and breaks SwiftUI's expected identity and lifecycle behavior. Environment Xcode Version 26.2 (17C52) iOS 26.2 simulator and device struct ContentView: View { @State var showMoreTabs = true struct DemoTab: View { var body: some View { Text(String(describing: type(of: self))) } } var body: some View { TabView { Tab("Home", systemImage: "house") { DemoTab() } Tab("Alerts", systemImage: "bell") { DemoTab() } if showMoreTabs { TabSection("Categories") { Tab("Climate", systemImage: "fan") { DemoTab() } Tab("Lights", systemImage: "lightbulb") { DemoTab() } } } Tab("Settings", systemImage: "gear") { List { Toggle("Show more Tabs", isOn: $showMoreTabs) } } } .tabViewBottomAccessory { AccessoryView() } .task { while true { try? await Task.sleep(for: .seconds(5)) if Task.isCancelled { break } print("toggling showMoreTabs") showMoreTabs.toggle() } } .tabBarMinimizeBehavior(.onScrollDown) } } struct AccessoryView: View { var body: some View { HStack { EnvironmentAccess() WithState() Stateless() } } } struct EnvironmentAccess: View { @Environment(\.tabViewBottomAccessoryPlacement) var placement var body: some View { // FIXME: EnvironmentAccess: @self, @identity, _placement changed. // Identity should be stable let _ = Self._printChanges() Text(String(describing: type(of: self))) } } struct WithState: View { @State var int = Int.random(in: 0...100) var body: some View { // FIXME: WithState: @self, @identity, _id changed. // Identity should be stable let _ = Self._printChanges() Text(String(describing: type(of: self))) } } struct Stateless: View { var body: some View { // Works as expected: Stateless: @self changed. let _ = Self._printChanges() Text(String(describing: type(of: self))) } } This bug seems to make accessing TabViewBottomAccessoryPlacement impossible without losing view identity; the demo code is affected by the bug. Accessing a value like @Environment(\.colorScheme) is similarly affected, making visually adapting the contents of the accessory to the TabView content without losing identity challenging if not impossible. Submitted as FB21627918.
0
0
53
3w
Need a progress bar during init a document
I have no idea how to do it: on MacOS, in Document.init(configuration: ReadConfiguration) I decode file, and restore objects from data, which in some cases could take a long time. Document isn't fully inited, so I have no access to it. But would like to have a progress bar on screen (easier to wait for done, for now). I know size, progress value, but no idea how to make view from object during init. I know, this question may be very stupid. init(configuration: ReadConfiguration) throws { guard let data = configuration.file.regularFileContents else { throw CocoaError(.fileReadCorruptFile) } let decoder = JSONDecoder() let flat = try decoder.decode(FlatDoc.self, from: data) print ("reverting \(flat.objects.count) objects...") ///This takes time, a lot of time, need progress bar ///Total is `flat.objects.count`, current is `objects.count` /// `Show me a way to the (next) progress bar!` revertObjects(from: flat.objects) print ("...done") } update: I defined var flatObjects in Document, and I can convert in .onAppear. struct TestApp: App { @State var isLoading = false ... ContentView(document: file.$document) .onAppear { isLoading = true Task {file.document.revertObjects()} isLoading = false } if isLoading { ProgressView() } ... } But progress bar never shows, only rainbow ball
Topic: UI Frameworks SubTopic: SwiftUI Tags:
0
0
116
3w
Table bug when row is selected and reorder is animated
Do you know if there is a work around to animate the reorder of a table without generating ghost rows? here is the code: var id = UUID() var name: String var value: Int } struct ContentView: View { @State var selectedNumber: UUID? @State var sortedBy: [KeyPathComparator<MyNumbers>] = [KeyPathComparator(\.name, order: .reverse)] @State var numbers: [MyNumbers] = { var numbersArray = [MyNumbers]() for i in 0..<100 { numbersArray.append(MyNumbers(name: "\(i)", value: i)) } return numbersArray }() var body: some View { Table(numbers, selection: $selectedNumber, sortOrder: $sortedBy) { TableColumn("names", value: \.name){ number in Text(number.name) } TableColumn("names", value: \.name){ number in Text(number.name) } }.onChange(of: sortedBy) { oldValue, newValue in withAnimation { numbers.sort(using: newValue) } } } } it generates ghost rows when the top row is selected and reorders twice, as you can see in the screenshot, the first six rows has two labels overlapped.
Topic: UI Frameworks SubTopic: SwiftUI
0
0
78
3w
Feedback generator was deactivated by its client more times than it was activated
When I use UIScrollView to Browse photos, sometime was crash. Issue Details: App: 美信 (Midea Connect) Problem: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Feedback generator was deactivated by its client more times than it was activated: <_UIZoomEdgeFeedbackGenerator: 0x33527cdc0>' First throw call stack Affected: 4 user out of thousands iOS Version: 18.0.1、26.1、26.2 What Works: All other users has no crash Same iOS version, no issues User Has Tried: The user experienced two crashes after opening the page hundreds of times
Topic: UI Frameworks SubTopic: UIKit
2
0
123
3w
controller.textDocumentProxy.documentContext not detecting pasted text in Gmail or Email apps
I found an issue related to Gmail and Email apps. When I try to fetch text using controller.textDocumentProxy.documentContext, it works fine every time in my original app and in the Messages app. However, in Gmail or Email apps, after pasting text, controller.textDocumentProxy.documentContext returns nil until the pasted text is edited. The same scenario works correctly in Messages and my original app. i'm trying it from my keyboard extension and my keyboard builded bases on KeyboardKit SDK when i jump to text Document Proxy it's referring me to UITextDocumentProxy
Topic: UI Frameworks SubTopic: UIKit
1
0
161
3w