Hello Dear Developers,
Is it only to me or in iOS 18 there's a problem with Settings.bundle, Im using my settings.bundle to set my enivement for my app but after upgrading to iOS 18 I can't see my Settings.Bundle in my settings iphone,
just to mention that I also updated my xcode to 16.
Anyone who has occur with this problem? :)
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
Created
In tvOS 18 the onMoveCommand is missing the first press after a view is loaded and every time the direction is changed. It also misses the first press on a button after a focus change. This appears to only impact the newer silver remote and not the older black remote or IR remotes.
With the code bellow press any direction 3 times and it will only log twice.
struct ButtonTest: View {
var body: some View {
VStack {
Button {
debugPrint("button 1")
} label: {
Text("Button 1")
}
Button {
debugPrint("button 2")
} label: {
Text("Button 2")
}
Button {
debugPrint("button 3")
} label: {
Text("Button 3")
}
}
.onMoveCommand(perform: { direction in
debugPrint("move \(direction)")
})
.padding()
}
}
Is there a SwiftUI version of NSControl.allowsExpansionToolTips? That is, showing a tool tip with the full text when (and only when) a text item is truncated?
Or do I need to use a hosting view to get that behavior?
Hello!
I discovered a bug on Catalyst about a three years ago but it still seems to be not fixed. My bug report number is FB9705748.
The Internet is silent on this so I'm even not sure, perhaps it's only me.
So to the problem. When you display UICollectionViewController or UIViewController that contains UICollectionView, interact with the collection view then dismiss the view controller, the displayed view controller isn't released if dismissal is done through navigation bar item.
The problem occurs only when the run target is My Mac (Mac Catalyst). Everything is fine when you run on iOS or via My Mac (Designed for iPad).
The sample project is uploaded to GitHub. It has a video that shows this strange behavior, see the log for 'deinit' messages.
I did have some workaround to fix this but it stops to work, presumable on the new macOS. Also, chances are that it's not only UICollectionView which initiates the glitch, it's just that I only encounter it with collection views.
When the home screen is in tinted mode in iOS 18, the widget gallery seems to display widgets with the background inset from the edge of the widget (i.e. negative padding).
You can see this behavior in the Apple News widget too, where the full-bleed content outside of the inset is very light. This only happens in the sample gallery, not when the widgets are placed on the home screen.
For my widgets, this outer edge contains important content and the clipping behavior makes the widgets look poorly designed when viewed in the gallery.
Is there any way to turn this behavior off and just show the widget normally in the gallery with no weird inset — the way it will actually display when added to the home screen?
If it matters, my widgets are currently configured with:
.contentMarginsDisabled()
.containerBackground(for: .widget) {
// ... (background color) */
}
It seems like it is no longer possible to open the main window of an app after the app has been launched by the system if the "Auto Start" functionality has been enabled.
I am using SMAppService.mainApp to enable to auto start of my app. It is shown in the macOS system settings and the app is automatically started - but the main window is not visible.
How can I change this behaviour so the main window of the app is always visible when started automatically?
I have not noticed this behaviour before the release of macOS Sequoia. My app is using Swift 6 and the latest version of macOS and Xcode.
Regards
Topic:
UI Frameworks
SubTopic:
SwiftUI
We're trying to implement a backup/restore data feature in our business productivity iPad app using UIDocumentPickerViewController and AppleArchive, but discovered odd behavior of [UIDocumentPickerViewController initForOpeningContentTypes: asCopy:YES] when reading large archive files from a USB drive.
We've duplicated this behavior with iPadOS 16.6.1 and 17.7 when building our app with Xcode 15.4 targeting minimum deployment of iPadOS 16. We haven't tested this with bleeding edge iPadOS 18.
Here's our Objective-C code which presents the picker:
NSArray* contentTypeArray = @[UTTypeAppleArchive];
UIDocumentPickerViewController* docPickerVC = [[UIDocumentPickerViewController alloc] initForOpeningContentTypes:contentTypeArray asCopy:YES];
docPickerVC.delegate = self;
docPickerVC.allowsMultipleSelection = NO;
docPickerVC.shouldShowFileExtensions = YES;
docPickerVC.modalPresentationStyle = UIModalPresentationPopover;
docPickerVC.popoverPresentationController.sourceView = self.view;
[self presentViewController:docPickerVC animated:YES completion:nil];
The UIDocumentPickerViewController remains visible until the selected external archive file has been copied from the USB drive to the app's local tmp sandbox. This may take several seconds due to the slow access speed of the USB drive. During this time the UIDocumentPickerViewController does NOT disable its tableview rows displaying files found on the USB drive. Even the most patient user will tap the desired filename a second (or third or fourth) time since the user's initial tap appears to have been ignored by UIDocumentPickerViewController, which lacks sufficient UI feedback showing it's busy copying the selected file.
When the user taps the file a second time, UIDocumentPickerViewController apparently begins to copy the archive file once again. The end result is a truncated copy of the selected file based on the time between taps. For instance, a 788 MB source archive may be copied as a 56 MB file. Here, the UIDocumentPickerDelegate receives a 56 MB file instead of the original 788 MB of data.
Not surprisingly, AppleArchive fails to decrypt the local copy of the archive because it's missing data. Instead of failing gracefully, AppleArchive crashes in AAArchiveStreamClose() (see forums post 765102 for details).
Does anyone know if there's a workaround for this strange behavior of UIDocumentPickerViewController?
My app uses the SwiftUI Map control to display annotations. When annotations contain buttons AND the map has an .onTapGesture modifier, annotation button taps aren’t always recognized.
Given the following ContentView, run it on an iOS device or simulator. Tap the buttons. Since iOS 18.0, some of the buttons won't respond to tap. I've also tried using the onTapGesture instead of a button, and that shows the same issue.
This was not a problem under iOS 17.x: it has only shown up for my users since updating to iOS 18. Additionally, this issue does not occur when running on either macOS 15.0 or visionOS 2.0 when running in "designed for iPad" mode.
Note that there was previously a tap issue on VisionOS 1.x (designed for iPad), where no tap gestures were received by annotations. I'm curious if this issue could be related.
I have filed a report in Feedback Assistant (FB15273909).
struct ContentView: View {
private let center = CLLocationCoordinate2D(latitude: 37.77925, longitude: -122.41924)
@State private var label: String = "tap a button"
@State private var locations: [Location] = []
var body: some View {
Map {
ForEach(locations) { location in
Annotation(location.name, coordinate: location.coordinate) {
Button(location.name) {
print("\(location.name) tapped")
label = "\(location.name) tapped"
}
.buttonStyle(.borderedProminent)
}
.annotationTitles(.hidden)
}
}
.onTapGesture { point in
print("Map tapped")
label = "map tapped"
}
.safeAreaInset(edge: .top) {
Text(label)
.padding()
.background(.thinMaterial)
.clipShape(.rect(cornerRadius: 10))
}
.navigationTitle("Test Page")
.navigationBarTitleDisplayMode(.inline)
.task {
for index in 1...16 {
locations.append(Location(name: "location \(index)",
coordinate: CLLocationCoordinate2D(latitude: center.latitude + Double.random(in: -0.02...0.02),
longitude: center.longitude + Double.random(in: -0.02...0.02))))
}
}
}
private struct Location: Identifiable {
let id: UUID = UUID()
let name: String
let coordinate: CLLocationCoordinate2D
}
}
#Preview {
ContentView()
}
I can't for the life of me get transitions and animations to work well with SwiftData and List on MacOS 15 and iOS 18.
I've included an example below, where I define several animations and a transition type, but they are all ignored.
How do I animate items being added to / removed from a List()?
I am attached to List() due to its support for selection, context menu, keyboard shortcuts, etc. If I would switch to ScrollView with VStack I would have to rebuild all of that.
Also, this is super basic and should just work, right?
Thanks for reading.
import SwiftUI
import SwiftData
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
/// Issues on iOS:
/// Items animate into and out of view, but I seem to have no control over the animation.
/// In the code here I've specified a 'bouncy' and a slow 'easeIn' animation: both are not triggered.
/// The code also specifies using a 'slide' transition, but it is ignored.
/// -> How do I control the transition and animation timing on iOS?
///
/// Issues on MacOS:
/// Items do not animate at all on MacOS! They instantly appear and are instantly removed.
/// -> How do I control the transition and animation timing on MacOS?
// animation added here -> has no effect?
@Query(animation: .bouncy) private var items: [Item]
var body: some View {
VStack {
Button("Add to list") {
// called without 'withAnimation' -> no animation
let newItem = Item(timestamp: Date())
modelContext.insert(newItem)
}
List() {
ForEach(items, id: \.self) { item in
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
.transition(.slide) // items do not slide in/out of view
.onTapGesture {
// called with 'withAnimation' -> no animation
withAnimation(.easeIn(duration: 2)) {
modelContext.delete(item)
}
}
}
.animation(.spring(duration: 3), value: items)
}
}
.padding()
}
}
#Preview {
ContentView()
.modelContainer(for: Item.self, inMemory: true)
}
Problem Description:
In a SwiftUI application, I've wrapped UIKit's UIPageViewController using UIViewControllerRepresentable, naming the wrapped class PagedInfiniteScrollView. This component causes navigation bar elements (title and buttons) to disappear.
This issue only occurs in Low Power Mode on a physical device.
Steps to Reproduce:
Enable Low Power Mode on a physical device and open the app's home page.
From the home page, open a detail sheet containing PagedInfiniteScrollView. This detail page include a navigation title and a toolbar button in the top-right corner. PagedInfiniteScrollView supports horizontal swiping to switch pages.
Tap the toolbar button in the top-right corner of the detail page to open an edit sheet.
Without making any changes, close the edit sheet and return to the detail page. On the detail page, swipe left and right on the PagedInfiniteScrollView.
Expected Result:
When swiping the PagedInfiniteScrollView, the navigation title and top-right toolbar button of the detail page should remain visible.
Actual Result:
When swiping the PagedInfiniteScrollView, the navigation title and top-right toolbar button of the detail page disappear.
import SwiftUI
@main
struct CalendarApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
import SwiftUI
struct ContentView: View {
@State private var showDetailSheet = false
@State private var currentPage: Int = 0
var body: some View {
NavigationStack {
Button {
showDetailSheet = true
} label: {
Text("show Calendar sheet")
}
.sheet(isPresented: $showDetailSheet) {
DetailSheet(currentPage: $currentPage)
}
}
}
}
struct DetailSheet: View {
@Binding var currentPage: Int
@State private var showEditSheet = false
var body: some View {
NavigationStack {
PagedInfiniteScrollView(content: { pageIndex in
Text("\(pageIndex)")
.frame(width: 200, height: 200)
.background(Color.blue)
},
currentPage: $currentPage)
.sheet(isPresented: $showEditSheet, content: {
Text("edit")
})
.navigationTitle("Detail")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItemGroup(placement: .topBarTrailing) {
Button {
showEditSheet = true
} label: {
Text("Edit")
}
}
}
}
}
}
import SwiftUI
import UIKit
struct PagedInfiniteScrollView<Content: View>: UIViewControllerRepresentable {
typealias UIViewControllerType = UIPageViewController
let content: (Int) -> Content
@Binding var currentPage: Int
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIPageViewController {
let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
pageViewController.dataSource = context.coordinator
pageViewController.delegate = context.coordinator
let initialViewController = UIHostingController(rootView: IdentifiableContent(index: currentPage, content: { content(currentPage) }))
pageViewController.setViewControllers([initialViewController], direction: .forward, animated: false, completion: nil)
return pageViewController
}
func updateUIViewController(_ uiViewController: UIPageViewController, context: Context) {
let currentViewController = uiViewController.viewControllers?.first as? UIHostingController<IdentifiableContent<Content>>
let currentIndex = currentViewController?.rootView.index ?? 0
if currentPage != currentIndex {
let direction: UIPageViewController.NavigationDirection = currentPage > currentIndex ? .forward : .reverse
let newViewController = UIHostingController(rootView: IdentifiableContent(index: currentPage, content: { content(currentPage) }))
uiViewController.setViewControllers([newViewController], direction: direction, animated: true, completion: nil)
}
}
class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var parent: PagedInfiniteScrollView
init(_ parent: PagedInfiniteScrollView) {
self.parent = parent
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let currentView = viewController as? UIHostingController<IdentifiableContent<Content>>, let currentIndex = currentView.rootView.index as Int? else {
return nil
}
let previousIndex = currentIndex - 1
return UIHostingController(rootView: IdentifiableContent(index: previousIndex, content: { parent.content(previousIndex) }))
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let currentView = viewController as? UIHostingController<IdentifiableContent<Content>>, let currentIndex = currentView.rootView.index as Int? else {
return nil
}
let nextIndex = currentIndex + 1
return UIHostingController(rootView: IdentifiableContent(index: nextIndex, content: { parent.content(nextIndex) }))
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed,
let currentView = pageViewController.viewControllers?.first as? UIHostingController<IdentifiableContent<Content>>,
let currentIndex = currentView.rootView.index as Int? {
parent.currentPage = currentIndex
}
}
}
}
extension PagedInfiniteScrollView {
struct IdentifiableContent<Content: View>: View {
let index: Int
let content: Content
init(index: Int, @ViewBuilder content: () -> Content) {
self.index = index
self.content = content()
}
var body: some View {
content
}
}
}
I found iPadOS18 displayed navigation bar incorrectly when transition from screen with hidden navigation bar to screen that show navigation bar.
I have 2 ViewController: FirstViewController and SecondViewController.
FirstViewController navigationBar set isHidden to be true (hidden) and
SecondViewController navigationBar set isHidden to be false (showing).
When transition from FirstViewController to SecondViewController, the navigation bar is displayed incorrectly as shown in picture below:
Actual
Expected
Note
I set hide navigation bar in viewWillAppear() in both ViewController
override func viewWillAppear(_ animated: Bool) {
navigationController?.setNavigationBarHidden(..., animated: true)
}
source code: https://github.com/ornthita/TestTabbar
If I put the phone flat on a table, the left and right swipe gestures is not working but up and down gestures works.
Only when I put the iPhone to some vertical degree, the left and right swipe works.
Tested on 2 iPhone 7 Plus and 2 iPhone 13.
Anyone has similar experience? If yes, why?
Hi.
I tried to launch SwiftUI preview.
But I got an error "AppLaunchTimeoutError"
I attach the diagnostics.
Does anyone know how to fix this problem?
memo.txt
Topic:
UI Frameworks
SubTopic:
SwiftUI
Hi.
Since Xcode 16 and/or iOS 18.0 (I upgraded at the same time), I have an strange effect in the lower (let's say) 20% section of the Navigation Bar when changing to another tab, and this independently if large titles are used or not. Mentioned section is brighter or darker than the rest of the Navigation Bar background, depending on which background tint is used. This effect lasts about 0.3 seconds, but is clearly visible, quite disturbing and new as of Xcode 16 and/or iOS 18.0.
I use the code below in AppDelegate to get a gradient coloured Navigation Bar background.
let appearance = UINavigationBarAppearance()
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
UINavigationBar.appearance().compactScrollEdgeAppearance = appearance
If I don't use above code., the background color is filled and without gradient. Subject effect doesn't show in this case.
The effect basically looks like when changing tab, the new Navigation Bar background doesn't clear right away, and keeps the background from the previous Navigation Bar for 0.3 seconds before new one Navigation Bar background is rendered.
I spent quite some time on changing every possible setting, in code as well as storyboard ... no success so far.
Any ideas how to disable this undesired animation?
I've been struggling with this issue since the release of macOS 15 Sequoia. I'm wondering if anyone else has encountered it or if anyone has a workaround to fix it.
Inserting a new element into the array that acts as data source for a SwiftUI List with a ForEach is never animated even if the insertion is wrapped in a withAnimation() call.
It seems that some other changes can be automated though: e.g. calls to shuffle() on the array successfully animate the changes.
This used to work fine on macOS 14, but stopped working on macOS 15.
I created a very simple project to reproduce the issue:
import SwiftUI
@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct IdentifiableItem: Identifiable {
let id = UUID()
var name: String { "Item \(id)" }
}
struct ContentView: View {
@State var items: [IdentifiableItem] = [
IdentifiableItem(), IdentifiableItem(), IdentifiableItem(), IdentifiableItem(), IdentifiableItem(),
IdentifiableItem(), IdentifiableItem(), IdentifiableItem(), IdentifiableItem(), IdentifiableItem(),
]
var body: some View {
List {
ForEach(items) { item in
Text(item.name)
}
}
Button("Add Item") {
withAnimation {
items.insert(IdentifiableItem(), at: 0)
}
}
Button("Shuffle Items") {
withAnimation {
items.shuffle()
}
}
}
}
How to reproduce
Copy the code below in an Xcode project.
Run it on macOS 15.
Hit the "Add Item" button
Expected: A new item is inserted with animation.
Result: A new item is inserted without animation.
How to prove this is a regression
Follow the same steps above but run on macOS 14.
A new item is inserted with animation.
Summary
In iOS 18, the UICollectionViewDelegate method
collectionView(_:targetIndexPathForMoveOfItemFromOriginalIndexPath:atCurrentIndexPath:toProposedIndexPath:)
is not being called when moving items in a UICollectionView. This method works as expected in iOS 17.5 and earlier versions.
Steps to Reproduce
Create a UICollectionView with drag and drop enabled.
Implement the UICollectionViewDelegate method:
func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveOfItemFromOriginalIndexPath originalIndexPath: IndexPath, atCurrentIndexPath currentIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
print("🐸 Move")
return proposedIndexPath
}
Run the app on iOS 18.
Attempt to drag and drop items within the collection view.
Expected Behavior
The method should be called during the drag and drop operation, and "🐸 Move" should be printed to the console.
Actual Behavior
The method is not called, and nothing is printed to the console. The drag and drop operation still occurs, but without invoking this delegate method.
Configuration
iOS Version: 18
Xcode Version: Xcode 16.0.0
We have recently added WidgetKit widgets to an existing product, and they've been working great on Macs using Big Sur and later. Recently, when installing a build on a Montery Mac, the widgets were no longer in Notification Center. After some trial and error, we discovered that if we build the project with Xcode 15.4, the widgets appear, but if we build with Xcode 16, the widgets vanish. This seems to happen on Macs running Big Sur or Monterey. The project is being built on Macs running Sonoma (both Apple Silicon and Intel).
Is there a build setting in Xcode 16 that may have this effect?
Hello
I'm working on implementing some changes to my app's tab bar, particularly to support some features in the new iPad floating tab bar, which has required me to adopt some of the new tab APIs from iOS 18.
The issue I've encountered is that I would like the tabs visible in regular (floating tab bar) and compact (bottom tab bar) to be slightly different. The compact variant should show a subset of the tabs visible on iPad. For example:
Floating tab bar: Use tabs A, B, C
Bottom tab bar: Use tabs A, B
I'm finding this quite difficult, especially in the scenario of split view on iPad, where the size class and tab bar location can change as the user interacts with the app.
I went down the route of changing my tab bar controller's tabs property when the trait collection changed
tabBarController.tabs = eligibleTabs
where eligibleTabs for compact passes tabs AB, and when in regular - ABC. This throws an exception
UIViewController cannot be shared between multiple UITab
*** Assertion failure in -[UITab viewController], UITab.m:173
I'm not sharing view controllers between tabs. I can only assume that the system doesn't like me passing the same values (always at least tabs A & B) multiple times to the tabs property.
I then later noticed a new iOS 18 property on UITabBarController - compactTabIdentifiers. This seemed like exactly what I was looking for: An optional filter to display only select root-level tabs when in a compact appearance. Default is nil, which would make all tabs available.
So I changed my implementation:
tabBarController.tabs = [tabA, tabB, tabC] tabBarController.compactTabIdentifiers = [tabAIdentifier, tabBIdentifier]
and don't make any explicit updates when split view is enabled.
Unfortunately this doesn't seem to work, at least not how I would expect it to. When enabling split view on iPad, the bottom tab bar appears, but it doesn't respect the tab identifiers I passed in tabBarController.compactTabIdentifiers.
I'm not sure if this a bug or that I'm not really understanding how to use tabBarController.compactTabIdentifiers.
Does anyone have any insight on this?
Topic:
UI Frameworks
SubTopic:
UIKit
I have an iOS app that relies on dynamic text size such that all fonts in the app respect the user's setting of Text Size in the iOS Settings app.
This app also runs on macOS via Mac Catalyst. But until macOS 14 Sonoma, there was no Text Size setting in the macOS Settings app. But even as of Sonoma, the Text Size setting isn't usable by 3rd party apps. And Sequoia doesn't seem to change that.
As a work around, my Mac Catalyst app provides its own Text Size setting. I was able to make it work by providing my own UIApplication subclass and overriding preferredContentSizeCategory. Under macOS 12 to macOS 14, this workaround works just fine and all fonts in the app created with code such as UIFont.preferredFont(forTextStyle:) gives appropriately sized fonts based on the overridden content size category.
However, this workaround stopped working with macOS 15 Sequoia. I've also tried code such as:
self.window.traitOverrides.preferredContentSizeCategory = myCustomSizeCategoryValue
and
self.window.maximumContentSizeCategory = myCustomSizeCategoryValue
self.window.minimumContentSizeCategory = myCustomSizeCategoryValue
in the scene delegate but that made no difference.
Is there any way to get code such as UIFont.preferredFont(forTextStyle:) to return an appropriately sized font based on some app provided content size category in a Mac Catalyst app running under macOS 15?
It sure would be nice if Mac Catalyst apps automatically responded to the macOS Text Size setting under Settings -> Accessibility -> Display -> Text Size just like a native iOS app.
Recently I've made 1 character mistake in my code and have hard time during searching what was the problem.
Basically I forgot to set dot near one of the frame modifiers and compiler did not warn me, but during app running I got 100% CPU and rocket increase of RAM (on real app). Feels like recursion, but no any hint in call stack inside Xcode on crash stop.
struct BadView: View {
var body: some View {
Color.red
frame(height: 36)
}
}
I would like to see at least warning for such cases. Problem may look simple on this small example, but if you added 1k+ lines after last compilation - searching this type of errors could be problematic when you have no idea what to search.