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

Activity

contactAccessPicker Ui referring to app name
We are using the contactAccessPicker modifier connected to a Button to allow the user to change the selection of contacts that he allows for use in our app. In the two places where the iOS UI screen refers to our app: "manage which contacts can access." on top, and below in the explanatory text, again , the value of is taken probably from the app's PRODUCT_NAME. Instead, we need it to be either CFBundleName or CFDisplayBundleName. In our case they are different (PRODUCT_NAME is legacy, reasons of rebranding, which is a very common reason in apps). Is there a specific reason why iOS is using PRODUCT_NAME (or something similar) in the contactAccessPicker UI screen instead of the user facing CFBundleName or CFDisplayBundleName? or is this a bug?
Topic: UI Frameworks SubTopic: SwiftUI
0
0
169
Jan ’25
SwiftUI TabView with .page Style: GeometryReader minX Not Updating on Page Scroll
I am working on a SwiftUI TabView with the .page style (indexDisplayMode: .never). I want to track the minX property of each tab's view using GeometryReader. However, I noticed inconsistent behavior when scrolling between pages. Here's the simplified code: import SwiftUI struct ContactScreenView: View { let text: String var body: some View { ZStack { Color.red.opacity(0.4).ignoresSafeArea() VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text(text) } .padding() } } } struct DemoView: View { @State private var selectedTab: Int = 0 var body: some View { VStack { TabView(selection: $selectedTab) { ContactScreenView(text: "followers") .background( GeometryReader(content: { geometry -> Color in let minX = geometry.frame(in: .global).minX print(minX) return Color.clear }) ) .tag(0) ContactScreenView(text: "following") .tag(1) ContactScreenView(text: "blocked") .tag(2) ContactScreenView(text: "Shared") .tag(3) } .tabViewStyle(.page(indexDisplayMode: .never)) } } } #Preview { DemoView() } Observed Behavior: When I scroll to the second page (index 1), the minX value updates correctly to screenWidth * 1, as expected. When I scroll to the third page (index 2), the minX value doesn't update at all. The ideal behavior would be for minX to update to screenWidth * 2 for the third page and so on, for subsequent pages. Expected Behavior: The minX value should correctly reflect the global position of each page as I scroll through the TabView. For example: Page 0: minX = 0 Page 1: minX = screenWidth * 1 Page 2: minX = screenWidth * 2 And so on.
Topic: UI Frameworks SubTopic: SwiftUI
1
0
264
Jan ’25
How to Maintain Background Color Consistency During ZoomTransitions in SwiftUI?
I’m currently working on a SwiftUI project and trying to implement a transition effect similar to ZoomTransitions. However, I’ve run into an issue. When transitioning from Page A to Page B using .navigationTransition(.zoom(sourceID: "world", in: animation)), Page A shrinks as expected, but its background color changes to the default white instead of the color I preset. I want the background color of Page A to remain consistent with my preset during the entire transition process. Here’s a simplified version of my code: Page A PartnerCard() .matchedTransitionSource(id: item.id, in: animation) Page B ``.navigationTransition(.zoom(sourceID: "world", in: animation))
Topic: UI Frameworks SubTopic: SwiftUI
0
0
280
Jan ’25
Variable modification in forEach
Hi! I'm trying to do a forEach loop on an array of objects. Here's my code : ForEach($individus) { $individu in if individu.reussite == true { individu.score -= 10 } else { individu.score = (individu.levees * 10) + 20 + individu.score } } I have an error on the code in the 'if' saying that "Type '()' cannot conform to 'View'", but I have no idea on how solving this problem.
Topic: UI Frameworks SubTopic: SwiftUI
2
0
258
Jan ’25
SwiftUI PKCanvasView bounds
I am creating a Bible app with SwiftUI using Text in the background and a PKCanvasView in the front to mark the text and take notes. The user can modify the font and its size and you can navigate to different books and chapters. Each chapter's text has a different size causing the PKCanvasView to have varying sizes. The width of the canvas is always the same but the height changes based on these parameters I just mentioned. If the chapter is long and the height of the canvas exceeds 4000 or some settings cause the text to make the views bound to go beyond 4000, the drawing will enlarge or appear to be occurring in a different location than my pencil. As soon as I lift my pencil, the drawing snaps to the place it belongs. var body: some View { HStack(spacing: 0) { // Main content container ScrollView { ZStack { // Text content VStack { if let chapter = viewModel.currentChapterText { HStack { Text(AttributedString(chapter.html(fontName: fontName, fontSize: fontSize, showVerses: showVerse, showFootnotes: showFootnotes))) .padding() .frame(width: textWidth, alignment: .leading) Color.clear } .frame(width: canvasWidth) } else { Text("Select a book to begin reading") .foregroundColor(.gray) } } // Drawing canvas overlay if showingDrawingTools { DrawingCanvasView( canvasView: $canvasView, toolPicker: toolPicker, frame: CGSize(width: deviceWidth, height: deviceHeight), onSave: saveDrawing ) } } } } .onChange(of: viewModel.currentChapter) { oldValue, newValue in print("BibleContentView - chapter text changed") } }
Topic: UI Frameworks SubTopic: SwiftUI
2
0
269
Jan ’25
Full Screen Tile: Left of Screen
I want to use Objective C language to implement a button, click the button to achieve the function of Menu Bar - Full Screen Tile - Left of Screen. What should I do? I couldn't find the relevant API.
Topic: UI Frameworks SubTopic: AppKit
0
0
366
Dec ’24
Using AsyncStream vs @Observable macro in SwiftUI (AVCam Sample Code)
I want to understand the utility of using AsyncStream when iOS 17 introduced @Observable macro where we can directly observe changes in the value of any variable in the model(& observation tracking can happen even outside SwiftUI view). So if I am observing a continuous stream of values, such as download progress of a file using AsyncStream in a SwiftUI view, the same can be observed in the same SwiftUI view using onChange(of:initial) of download progress (stored as a property in model object). I am looking for benefits, drawbacks, & limitations of both approaches. Specifically, my question is with regards to AVCam sample code by Apple where they observe few states as follows. This is done in CameraModel class which is attached to SwiftUI view. // MARK: - Internal state observations // Set up camera's state observations. private func observeState() { Task { // Await new thumbnails that the media library generates when saving a file. for await thumbnail in mediaLibrary.thumbnails.compactMap({ $0 }) { self.thumbnail = thumbnail } } Task { // Await new capture activity values from the capture service. for await activity in await captureService.$captureActivity.values { if activity.willCapture { // Flash the screen to indicate capture is starting. flashScreen() } else { // Forward the activity to the UI. captureActivity = activity } } } Task { // Await updates to the capabilities that the capture service advertises. for await capabilities in await captureService.$captureCapabilities.values { isHDRVideoSupported = capabilities.isHDRSupported cameraState.isVideoHDRSupported = capabilities.isHDRSupported } } Task { // Await updates to a person's interaction with the Camera Control HUD. for await isShowingFullscreenControls in await captureService.$isShowingFullscreenControls.values { withAnimation { // Prefer showing a minimized UI when capture controls enter a fullscreen appearance. prefersMinimizedUI = isShowingFullscreenControls } } } } If we see the structure CaptureCapabilities, it is a small structure with two Bool members. These changes could have been directly observed by a SwiftUI view. I wonder if there is a specific advantage or reason to use AsyncStream here & continuously iterate over changes in a for loop. /// A structure that represents the capture capabilities of `CaptureService` in /// its current configuration. struct CaptureCapabilities { let isLivePhotoCaptureSupported: Bool let isHDRSupported: Bool init(isLivePhotoCaptureSupported: Bool = false, isHDRSupported: Bool = false) { self.isLivePhotoCaptureSupported = isLivePhotoCaptureSupported self.isHDRSupported = isHDRSupported } static let unknown = CaptureCapabilities() }
0
0
376
Dec ’24
Bug in iOS 18 with NSTimeZone and DatePicker
iOS 18 broke some functionality in my Objective-C app with regard to using the DatePicker. The key lines are as follows: datePicker.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:timezoneOffset]; datePicker.date = [NSDate date]; When timezoneOffset is -29380, the value for San Francisco, the Date Picker is a whole MONTH off. It shows November instead of December. But when it is -29359, the value for Seattle, which is in the same time zone (PST), it shows the correct month. In fact, even towns surrounding San Francisco usually return the correct value. Some other cities in other time zones also cause the Date Picker to be a month off.
7
0
765
Jan ’25
UIDocumentBrowserViewController - adjust order and color of navigation bar items
I'm using UIDocumentBrowserViewController. This view controller automatically creates a TabView with navigation titles and up to two trailing navigation bar items. To visualize this, open the Files app by Apple on an iPhone. I want to do the following: Add a third button and place it farthest on the trailing side. Keep all three buttons blue (the default color), but adjust the color of the navigation title to use the primary text color (it is also currently blue, by default) Button Order If my button is represented by C, then the order from left-to-right or leading-to-trailing should be A B C. I tried to add it by using additionaltrailingnavigationbarbuttonitems: class DocumentBrowserViewController: UIDocumentBrowserViewController, UIDocumentBrowserViewControllerDelegate { override func viewDidLoad() { super.viewDidLoad() let button = UIBarButtonItem(...) additionalTrailingNavigationBarButtonItems.append(button) } } This always adds it as the leftmost trailing item. The order when the view loads is C A B, where C represents my button. Here are some things I've tried: Add it in viewWillAppear - same results. Add it in viewDidAppear - same results. Add it using rightBarButtonItems - does not show up at all. insert it at: 0 instead of appending it - same results. Add it with a delay using DispatchQueue.main.async - same results. After some experimentation, I realized that the arrays referenced by additionalTrailingNavigationBarButtons and rightBarButtonItems seem to be empty, other than my own button. This is the case even if the DispatchQueue delay is so long that the view has already rendered and the two default buttons are clearly visible. So I'm not sure how to place my button relative to these, since I can't figure out where they actually are in the view controller's properties. How do I put my button farther to the trailing/right side of these two default buttons? Title Color The navigation titles created by UIDocumentBrowserViewController are blue when not in their inline format. I want them to use the primary text color instead. In viewDidLoad, I could do something like this: UINavigationBar.appearance().tintColor = UIColor.label This will change the title color to white or black, but it will also change the color of the buttons. I've tried various approaches like titleTextAttributes, and none of them seem to work with this view controller. How do I change just the color of the navigation title, and not the color of the navigation bar items?
Topic: UI Frameworks SubTopic: UIKit
0
0
350
Jan ’25
"Add-on" services no longer supported?
Our MacOS app has for some time been able to create so-called "add-on" services, which are dynamically written to individual bundles in ~/Library/Services/ (as opposed to being statically defined in the app's Info.plist). These worked fine for a long time until recently. They still appear in other app Services menus, but do not get as far as calling the specified instance method in our app. Does anyone know if add-on services are no longer supported? Perhaps due to some new security constraint? The documentation on app services in general seems to be out of date. I did try copying the add-on service definition from the add-on plist into the app's Info.plist. That seemed to work, so the basic specification doesn't seem to have changed.
Topic: UI Frameworks SubTopic: AppKit
0
0
272
Jan ’25
How do I make a UIViewRepresentable beneath SwiftUI elements ignore touches to these elements?
Hello, and an early "Merry Christmas" to all, I'm building a SwiftUI app, and one of my Views is a fullscreen UIViewRepresentable (SpriteView) beneath a SwiftUI interface. Whenever the user interacts with any SwiftUI element, the UIView registers a hit in touchesBegan(). For example, my UIView has logic for pinching (not implemented via UIGestureRecognizer), so whenever the user holds down a SwiftUI element while touching the UIView, that counts as two touches to the UIView which invokes the pinching logic. Things I've tried to block SwiftUI from passing the gesture down to the UIView: Adding opaque elements beneath control elements Adding gestures to the elements above Adding gesture masks to the gestures above Converting eligible elements to Buttons (since those seem immune) Adding SpriteViews beneath those elements to absorb gestures So far nothing has worked. As long as the UIView is beneath SwiftUI elements, any interactions with those elements will be registered as a hit. The obvious solution is to track each SwiftUI element's size and coordinates with respect to the UIView's coordinate space, then use exclusion areas, but this is both a pain and expensive, and I find it hard to believe this is the best fix for such a seemingly basic problem. I'm probably overlooking something basic, so any suggestions will be greatly appreciated
0
0
434
Dec ’24
Retrieve input field text as a keyboard extension in Swift
I am able to retrieve the text in the input field by doing: let contextBeforeInput = textDocumentProxy.documentContextBeforeInput ?? "" let contextAfterInput = textDocumentProxy.documentContextAfterInput ?? "" let fullText = contextBeforeInput + contextAfterInput However, when I'm pasting text into the input field, textDocumentProxy.documentContextBeforeInput refuses to return the entire text from the input field but instead only returns the last two sentences. I have tried this with the input fields in WhatsApp, Signal, and Telegram and it's all the same, so it doesn't seem to be caused by the specific app. At first I thought it was a limitation imposed by Apple but other third party keyboard extensions such as Grammarly are able to pick up the whole pasted text from the input field, so how are they doing it?
Topic: UI Frameworks SubTopic: UIKit
0
0
234
Jan ’25
Unexpected Insertion of U+2004 (Space) When Using UITextView with Pinyin Input on iOS 18
I encountered an issue with UITextView on iOS 18 where, when typing Pinyin, extra Unicode characters such as U+2004 are inserted unexpectedly. This occurs when using a Chinese input method. Steps to Reproduce: 1. Set up a UITextView with a standard delegate implementation. 2. Use a Pinyin input method to type the character “ㄨ”. 3. Observe that after the character “ㄨ” is typed, extra spaces (U+2004) are inserted automatically between the characters. Code Example: class ViewController: UIViewController { @IBOutlet weak var textView: UITextView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } } extension ViewController: UITextViewDelegate { func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { print("shouldChangeTextIn: range \(range)") print("shouldChangeTextIn: replacementText \(text)") return true } func textViewDidChange(_ textView: UITextView) { let currentText = textView.text ?? "" let unicodeValues = currentText.unicodeScalars.map { String(format: "U+%04X", $0.value) }.joined(separator: " ") print("textViewDidChange: textView.text: \(currentText)") print("textViewDidChange: Unicode Scalars: \(unicodeValues)") } } Output: shouldChangeTextIn: range {0, 0} shouldChangeTextIn: replacementText ㄨ textViewDidChange: textView.text: ㄨ textViewDidChange: Unicode Scalars: U+3128 ------------------------ shouldChangeTextIn: range {1, 0} shouldChangeTextIn: replacementText ㄨ textViewDidChange: textView.text: ㄨ ㄨ textViewDidChange: Unicode Scalars: U+3128 U+2004 U+3128 ------------------------ shouldChangeTextIn: range {3, 0} shouldChangeTextIn: replacementText ㄨ textViewDidChange: textView.text: ㄨ ㄨ ㄨ textViewDidChange: Unicode Scalars: U+3128 U+2004 U+3128 U+2004 U+3128 This issue may affect text processing, especially in cases where precise text manipulation is required, such as calculating ranges in shouldChangeTextIn.
5
0
1k
Jan ’25
Popover in full-screen apps doesn't keep menu bar open
I have an app that acts as an agent (no dock/app, just menu bar icon). When the icon is clicked, I show a popover with a small user interface. This works great, however, there is an issue. When a certain app is in full-screen and then my menu bar icon is clicked, the user interface shows just fine, until the mouse is moved outside the menu bar - then the user interface stays but the menu bar dismisses and closes. Is there a way to keep the menu bar open, like when clicking on Control Center, in full-screen apps? This is how I open my popover: if let button = statusItem.button { if popover.isShown { self.popover.performClose(sender) } else { popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY) popover.contentViewController?.view.window?.makeKey() } } }
2
0
225
Jan ’25
NavigationSplitView detail view not updating
I have a NavigationSplitView with all three columns, and NavigationLinks in the sidebar to present different Lists for the content column. When a list item is selected in the content view, I want to present a view in the detail view. Since different detail views should be presented for different content views, I represent state like this (some details omitted for space): // Which detail view to show in the third column enum DetailViewKind: Equatable { case blank case localEnv(RegistryEntry) case package(SearchResult) } // Which link in the sidebar was tapped enum SidebarMenuItem: Int, Hashable, CaseIterable { case home case localEnvs case remoteEnvs case packageSearch } // Binds to a DetailViewKind, defines the activate SidebarMenuItem struct SidebarView: View { @State private var selectedMenuItem: SidebarMenuItem? @Binding var selectedDetailView: DetailViewKind var body: some View { VStack(alignment: .leading, spacing: 32) { SidebarHeaderView() Divider() // Creates the navigationLinks with a SidebarMenuRowView as labels SidebarMenuView(selectedMenuItem: $selectedMenuItem, selectedDetailView: $selectedDetailView) Spacer() Divider() SidebarFooterView() } .padding() .frame(alignment: .leading) } } struct SidebarMenuRowView: View { var menuItem: SidebarMenuItem @Binding var selectedMenuItem: SidebarMenuItem? @Binding var selectedDetailView: DetailViewKind private var isSelected: Bool { return menuItem == selectedMenuItem } var body: some View { HStack { Image(systemName: menuItem.systemImageName).imageScale(.small) Text(menuItem.title) Spacer() } .padding(.leading) .frame(height: 24) .foregroundStyle(isSelected ? Color.primaryAccent : Color.primary) .background(isSelected ? Color.menuSelection : Color.clear) .clipShape(RoundedRectangle(cornerRadius: 10)) .navigationDestination(for: SidebarMenuItem.self) { item in navigationDestinationFor(menuItem: item, detailView: $selectedDetailView) } .onTapGesture { if menuItem != selectedMenuItem { selectedMenuItem = menuItem } } } } // Determines which detail view to present struct DetailView: View { @Binding var selectedDetailView: DetailViewKind var innerView: some View { switch selectedDetailView { case .blank: AnyView(Text("Make a selection") .font(.subheadline) .foregroundStyle(.secondary) .navigationSplitViewColumnWidth(min: 200, ideal: 350)) case .localEnv(let regEntry): AnyView(EnvironmentDetailView(regEntry: regEntry)) case .package(let searchResult): AnyView(PackageDetailView(searchResult: searchResult)) } } var body: some View { innerView } } struct ContentView: View { @State private var detailView: DetailViewKind = .blank var body: some View { NavigationSplitView { SidebarView(selectedDetailView: $detailView) .navigationSplitViewColumnWidth(175) } content: { HomeView() .navigationSplitViewColumnWidth(min: 300, ideal: 450) } detail: { DetailView(selectedDetailView: $detailView) } } } My issue is that the detail view is not updated when the ContentView's detailView property is updated. I've verified that the value itself is changing, but the view is not. I searched around to see why this would be (this is my first Swift/SwiftUI application) and from what I gather a @Binding alone will not cause a view to be updated, that binding either needs to be used in the view hierarchy, or it needs to be stored as a @State property that gets updated when the binding value changes. I added a dummy @State property to DetailView and that still doesn't work, so I'm a little confused: struct DetailView: View { @Binding var selectedDetailView: DetailViewKind @State private var dummyProp: DetailViewKind? var innerView: some View { switch selectedDetailView { case .blank: AnyView(Text("Make a selection") .font(.subheadline) .foregroundStyle(.secondary) .navigationSplitViewColumnWidth(min: 200, ideal: 350)) case .localEnv(let regEntry): AnyView(EnvironmentDetailView(regEntry: regEntry)) case .package(let searchResult): AnyView(PackageDetailView(searchResult: searchResult)) } } var body: some View { innerView.onChange(of: selectedDetailView) { dummyProp = selectedDetailView } } } Any ideas?
Topic: UI Frameworks SubTopic: SwiftUI
1
0
443
Jan ’25
QLPreviewingController can access previewed file, but cannot load files referenced by the previewed file
I have an app on the Mac App Store (so sandboxed) that includes a QuickLook Preview Extension that targets Markdown files. It established a QLPreviewingController instance for the macOS QuickLook system to access and it works. I'm in the process of updating it so that it displays inline images referenced in the file as well as styling the file's text. However, despite setting Downloads folder read-only access permission (and user-selected, though I know that shouldn't be required: no open/save dialogs here) in the extension's entitlements, Sandbox refuses too allow access to the test image: I always get a deny(1) file-read-data error in the log. FWIW, the test file is referenced in the source Markdown as an absolute unix file path. I've tried different signings and no joy. I’ve tried placing the referenced image in various other locations. Also no joy. All I can display is the error-case bundle image for 'missing image'. Question is, is this simply something that QuickLook extensions cannot do from within the sandbox, or am I missing something? Is there anything extra I can do to debug this?
0
0
405
Jan ’25
Start tvOS SideBar Menu Collapsed
I'm trying to make the side bar menu on my tvOS app have the same behavior of Apple's tvOS App. I would like to have the side menu collapsed at the cold start of the app. I'm trying to achieve this by using the defaultFocus view modifier, which should make the button inside the TabView focused at the start of the app. But no matter what I do, the side bar always steels the focus from the inside button. struct ContentView: View { enum Tabs { case viewA case viewB } enum ScreenElements { case button case tab } @FocusState private var focusedElement: ScreenElements? @State private var selectedTab: Tabs? = nil var body: some View { Group { TabView(selection: $selectedTab) { Tab("View A", image: "square", value: .viewA) { Button("View A Button", action: {}) .frame(maxWidth: .infinity, alignment: .center) .focused($focusedElement, equals: .button) } } .tabViewStyle(.sidebarAdaptable) .focused($focusedElement, equals: .tab) } .defaultFocus($focusedElement, .button, priority: .userInitiated) } } Is there a way to start the side bar menu collapsed at the start up of the app?
0
0
387
Jan ’25
ishidden not working
I set the isHidden property of a view in traitCollectionDidChange and found that sometime it does not take effect after being set(value of isHidden actually not changed either). It looks like the setting does not take effect when triggered an even number of times, but it is normal when triggered an odd number of times. When setting isHidden, what actually goes into is [UIView (Rendering) setHidden:], which internally calls [UIView _ bitFlagValueAfterIncrementingHiddenManagement CountForKey: withIncrement: bitFlagValue:] to handle the relevant logic of "_UIViewPendingHiddenCount". Is this issue related to this part of the processing? returning 0 after calling seems normal This view is a UIStackView, and it is uncertain whether it is related to the type of view
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
370
Jan ’25