Discuss the different user interface frameworks available for your app.

All subtopics

Post

Replies

Boosts

Views

Activity

Page-based layouts with TextKit 2?
In the "old" TextKit, page-based layout is accomplished by providing an array of NSTextContainers to NSLayoutManager, each with its own NSTextView. TextKit 2, NSTextLayoutManager allows only a single text container. Additionally, NSTextParagraph seems to be the only concrete NSTextElement class. Paragraphs often need to break across page boundaries. How would one implement page-based layout in TextKit 2?
4
0
3.0k
Jun ’21
How to Use Quick Notes Using SwiftUI
I am trying to implement Quick Notes through SwiftUI, rather than UIKit or AppKit. I am unsure if the behaviour below is expected, or due to a bug. I have already successfully implemented NSUserActivity for Handoff, Spotlight and Siri Reminders, using the .userActivity() view modifier. These NSUserActivity instances use the NSUserActivity.userInfo dictionary to store and correctly restore the content through the .onContinueUserActivity(perform: ) methods. Quick Notes requires using the .persistentIdentifier or .targetContentIdentifier properties, rather than the .userInfo dictionary alone. However, when I set these either of these to unique identifiers using the code below, they are not correctly stored within the useractivity. MyView() .userActivity(ActivityString, updateUserActivity) private func updateUserActivity(_ activity: NSUserActivity) {     activity.isEligibleForSearch = true     activity.isEligibleForHandoff = true     activity.title = "Title"     activity.targetContentIdentifier = myItemUniqueID     activity.persistentIdentifier = myItemUniqueID     activity.userInfo = ["id": myItemUniqueID]     print(activity.targetContentIdentifier) // Correctly prints     print(activity.persistentIdentifier) // Correctly prints     print(activity.userInfo) // Correctly prints     } The identifiers print correctly when setting the user activity above. However, when restoring the user activity (tested through Handoff and Spotlight Search), the targetContentIdentifier and persistentIdentifier strings are empty. MyView()     .onContinueUserActivity(ActivityString, perform: continueUserActivity) private func continueUserActivity(_ activity: NSUserActivity) {     print(activity.persistentIdentifier) // Nil     print(activity.targetContentIdentifier) // Nil     print(activity.userInfo) // Correctly prints     } Is there something else I must do, or is this unexpected behaviour?
1
0
1.4k
Sep ’21
ImportFromDevicesCommands - The operation couldn’t be completed. (Cocoa error 66563.)
I am trying to use import from iPhone option as shown in WWDC session. I added code  WindowGroup {             ContentView()                 .environment(\.managedObjectContext, persistenceController.container.viewContext)                      }         .commands {             ImportFromDevicesCommands()         } ContentView.swift is  List {                 ForEach(items) { item in                     NavigationLink {                         Text("Item at \(item.timestamp!, formatter: itemFormatter)")                     } label: {                         Text(item.timestamp!, formatter: itemFormatter)                     }                 }                 .onDelete(perform: deleteItems)             }             .importsItemProviders([.image,.png,.jpeg,.rawImage], onImport: { providers in                 print("checking reachability")                 return true             }) The importsItemProviders block itself is not executed and not printing anything. In addition I am getting alert The operation couldn’t be completed. (Cocoa error 66563.) Is there anything to add for making this functionality work ?
3
0
1.2k
Nov ’21
What does this UICollectionView exception mean?
In my application using UICollectionViewDiffableDataSource and compositional layout, I saw this exception Thread 1: "This solver does not handle estimated items so this method does nothing. Are you calling this in error?" that was thrown in dataSource.apply(snapshot, animatingDifferences: animated). I don't understand what it is telling me and how I should fix it. Any idea?
4
0
1k
Feb ’22
UISplitViewController and UITabBarController in iOS 15 is always full screen
I'm reworking my app and update code and design. Because my app is one both iPhone and iPad, i'm using Splitview to handle the configurations. But my app has 4 section that I manage using a Tab bar and each tab has a SplitView. As you can see in images, the problem is that if I attach directly the UISplitViewController to UITabBarController you don't see two columns but only one (the primary or secondary view) both iPhone landscape orientation and iPad. A solution that I found is to attach the splitviewcontroller to a view that contains a ContainerViewController e connect the split view to this container. If you do this, you see the split view work correctly ma the problem is the customization of appearance (look at image 3) So may questions are: why I have to embed a split view in a container view controller and i can't connect it directly to tabbar as we done until now? Is there an other better solution then put a split view in a containerView? Thank you )
2
0
1.6k
Mar ’22
What is "focus"?
In iOS 15 SDK you added the new FocusState API in SwiftUI. However there is no discussion or explanation anywhere that I could find, which explains: What exactly is "focus"? What isn't focus? What is the relationship between FocusState and accessibility focus? What is the relationship between whether a SecureField is being edited, and whether it's "focused"? Example: Lets say my tvOS app has an on-screen keyboard, where the user uses the remote's directional controls to move focus around to the letter buttons. To enter their password, they focus the password field, then click the center button to activate it. Now that it's active, they move focus to each letter of their password and click on each one: P... A... S... S... W... R... D... !... then they move focus to the "Submit" button and click. In this case, while the SecureField is being edited, focus moves around to a bunch of different buttons. The point of this example is that, if SecureField had a public "isBeingEdited" property, then it would be TRUE even while the field is not focused. However most Workday's designers interpret "focused" as being totally equivalent to "isBeingEdited" because in a web browser, tabbing out of a field makes it stop being edited. What is Apple's intent here? When not using a remote or physical keyboard or screen-reader, how is focus supposed to relate to whether a field is being edited? Does this relationship change when a user now has a bluetooth keyboard connected and Full Keyboard Access is turned ON? How does this correlate with accessibility focus? I cannot find any documentation from Apple that explains what focus is, or how this is supposed to work in SwiftUI in the various different scenarios where the concept of "focus" is relevant. Do you have a link to something current that explains how it's supposed to work so that we will know if there's a bug? Last question: how can we make the iOS simulator treat the physical keyboard as if it was a bluetooth keyboard to be used for focus-based keyboard navigation?
5
0
1.6k
Apr ’22
UICollectionView How to make a cell size itself dynamically based on its UIHostingConfiguration?
I have made an UICollectionView in which you can double tap a cell to resize it. I'm using a CompositionalLayout, a DiffableDataSource and the new UIHostingConfiguration hosting a SwiftUI View which depends on an ObservableObject. The resizing is triggered by updating the height property of the ObservableObject. That causes the SwiftUI View to change its frame which leads to the collectionView automatically resizing the cell. The caveat is that it does so immediately without animation only jumping between the old and the new frame of the view. The ideal end-goal would be to be able to add a .animation() modifier to the SwiftUI View that then determines animation for both view and cell. Doing so now without additional setup makes the SwiftUI View animate but not the cell. Is there a way to make the cell (orange) follow the size of the view (green) dynamically? The proper way to manipulate the cell animation (as far as I known) is to override initialLayoutAttributesForAppearingItem() and finalLayoutAttributesForDisappearingItem() but since the cell just changes and doesn't appear/disappear they don't have an effect. One could also think of Auto Layout constraints to archive this but I don’t think they are usable with UIHostingConfiguration? I've also tried: subclassing UICollectionViewCell and overriding apply(_ layoutAttributes: UICollectionViewLayoutAttributes) but it only effects the orange cell-background on initial appearance. to put layout.invalidateLayout() or collectionView.layoutIfNeeded() inside UIView.animate() but it does not seem to have an effect on the size change. Any thoughts, hints, ideas are greatly appreciated ✌️ Cheers! Here is the code I used for the first gif: struct CellContentModel { var height: CGFloat? = 100 } class CellContentController: ObservableObject, Identifiable { let id = UUID() @Published var cellContentModel: CellContentModel init(cellContentModel: CellContentModel) { self.cellContentModel = cellContentModel } } class DataStore { var data: [CellContentController] var dataById: [CellContentController.ID: CellContentController] init(data: [CellContentController]) { self.data = data self.dataById = Dictionary(uniqueKeysWithValues: data.map { ($0.id, $0) } ) } static let testData = [ CellContentController(cellContentModel: CellContentModel()), CellContentController(cellContentModel: CellContentModel(height: 80)), CellContentController(cellContentModel: CellContentModel()) ] } class CollectionViewController: UIViewController { enum Section { case first } var dataStore = DataStore(data: DataStore.testData) private var layout: UICollectionViewCompositionalLayout! private var collectionView: UICollectionView! private var dataSource: UICollectionViewDiffableDataSource<Section, CellContentController.ID>! override func loadView() { createLayout() createCollectionView() createDataSource() view = collectionView } } // - MARK: Layout extension CollectionViewController { func createLayout() { let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50)) let Item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.8), heightDimension: .estimated(300)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [Item]) let section = NSCollectionLayoutSection(group: group) layout = .init(section: section) } } // - MARK: CollectionView extension CollectionViewController { func createCollectionView() { collectionView = .init(frame: .zero, collectionViewLayout: layout) let doubleTapGestureRecognizer = DoubleTapGestureRecognizer() doubleTapGestureRecognizer.doubleTapAction = { [unowned self] touch, _ in let touchLocation = touch.location(in: collectionView) guard let touchedIndexPath = collectionView.indexPathForItem(at: touchLocation) else { return } let touchedItemIdentifier = dataSource.itemIdentifier(for: touchedIndexPath)! dataStore.dataById[touchedItemIdentifier]!.cellContentModel.height = dataStore.dataById[touchedItemIdentifier]!.cellContentModel.height == 100 ? nil : 100 } collectionView.addGestureRecognizer(doubleTapGestureRecognizer) } } // - MARK: DataSource extension CollectionViewController { func createDataSource() { let cellRegistration = UICollectionView.CellRegistration<UICollectionViewCell, CellContentController.ID>() { cell, indexPath, itemIdentifier in let cellContentController = self.dataStore.dataById[itemIdentifier]! cell.contentConfiguration = UIHostingConfiguration { TextView(cellContentController: cellContentController) } .background(.orange) } dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier) } var initialSnapshot = NSDiffableDataSourceSnapshot<Section, CellContentController.ID>() initialSnapshot.appendSections([Section.first]) initialSnapshot.appendItems(dataStore.data.map{ $0.id }, toSection: Section.first) dataSource.applySnapshotUsingReloadData(initialSnapshot) } } class DoubleTapGestureRecognizer: UITapGestureRecognizer { var doubleTapAction: ((UITouch, UIEvent) -> Void)? override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) { if touches.first!.tapCount == 2 { doubleTapAction?(touches.first!, event) } } } struct TextView: View { @StateObject var cellContentController: CellContentController var body: some View { Text(cellContentController.cellContentModel.height?.description ?? "nil") .frame(height: cellContentController.cellContentModel.height, alignment: .top) .background(.green) } }
2
1
3.0k
Jul ’22
How to ignore the safe area when using keyboardLayoutGuide
I have a full screen list and want to use the new keyboardLayoutGuide constraint, but by default it uses the safe area inset. How can I disable this so my list goes all the way to the bottom of the screen when the keyboard is not shown? NSLayoutConstraint.activate([ collectionView.topAnchor.constraint(equalTo: view.topAnchor), collectionView.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor), collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), collectionView.trailingAnchor.constraint(equalTo:  view.trailingAnchor) ])
3
1
2.3k
Sep ’22
Disable Smart Selection feature on PKCanvasView
I've been trying to disable the "Smart Selection" feature introduced in https://developer.apple.com/wwdc20/10107 from a PKCanvasView. This feature could be very useful for some apps but if you want to start from a clean state canvas it might get in your way as you add gestures and interactions. Is there any way to opt out from it? The #WWDC20-10107 video demonstrates the "Smart Selection" feature at around 1:27.
1
2
967
Jun ’23
WWDC21 Building a Great App: Export fails
Yes, I know WWDC21 was a long time ago but here it is August 2023 and I am looking at the "Building a Great App with SwiftUI. Following along with the Session 1 and 2 videos, I get to the part where you add an Export command. Only, the Export dialog does not appear. The "completed" session 2 source also fails to display an Export dialog. In fact there appears to be no definition for an Export view. I've searched the web, including the Apple forum, for this problem but it looks like no one has encountered this bug. Did anyone ever get this Great App to work?
0
0
526
Aug ’23
DiffableDataSource failing to reconfigure cell
I keep getting random crashes, when attempting to reconfigure an existing item. I check immediately for that if the item identifier exists in the data source and do not attempt to configure it if it's not. This is there error message: "Attempted to reconfigure item identifier that does not exist in the snapshot: ..." Fatal Exception: NSInternalInconsistencyException 0 CoreFoundation 0x9cb4 __exceptionPreprocess 1 libobjc.A.dylib 0x183d0 objc_exception_throw 2 Foundation 0x4e154c _userInfoForFileAndLine 3 UIKitCore 0xa44a8 -[__UIDiffableDataSourceSnapshot _validateReloadUpdateThrowingIfNeeded:] 4 UIKitCore 0xa2ed8 -[__UIDiffableDataSourceSnapshot _commitUpdateAtomic:] 5 UIKitCore 0x561048 -[__UIDiffableDataSourceSnapshot reconfigureItemsWithIdentifiers:] 6 libswiftUIKit.dylib 0x35d0c NSDiffableDataSourceSnapshot.deleteItems(_:) 7 Trulia 0x45380c closure #1 in ActivityFeedV3ViewController.updateUI(for:) 8 Trulia 0x4c4f58 thunk for @escaping @callee_guaranteed () -> () (<compiler-generated>)
2
0
867
Sep ’23
SwiftUI BottomBar Toolbar on parent view breaks leading navigation swipe on iOS 17.0
After Updating my app to iOS 17.0 I noticed some odd behavior when swiping a detail view away with a parent view that has a toolbar with a ToolbarItem(placement: .bottomBar). As the user starts a leading swipe gesture to navigate back to the previous view the parent navigation title strangely animates to the center and the leading nav bar button disappears. If the user stops this gesture at any point before completing the swipe they will be stuck in the detail view as the leading nav button has disappeared. This only seems to be an issue if one attempts to swipe back to the parent view and not when the leading nav button is tapped. The following is the minimum code to reproduce this issue for me. I am testing on a physical device on iOS 17.0 with Xcode Version 15.0 (15A240d). struct ToolbarIssueView: View { var body: some View { NavigationStack { NavigationLink { Text("Detail View") .navigationTitle("Detail") } label: { Text("To Detail View") } .toolbar { // This seems to cause strange behavior ToolbarItem(placement: .bottomBar) { Text("Bottom Bar Content") } } .navigationTitle("Main") } } } I understand that this bottom bar could easily be replaced with a .safeAreaInset(edges: .bottom) but I would prefer to use the more standard ToolbarItem(placement: .bottomBar). If anyone has any fixes for this issue or know what I am missing I would love to hear it!
9
9
2.7k
Oct ’23
Autosaving NSDocument memory leak with NSWindow and NSToolbar - NSDocumentTitlebarPopoverViewController leaks
I think I have found a Cocoa memory leak that is resulting in my NSDocuments being retained after they have been closed by the user. I am posting here to see if anyone else has encountered this, and if so, what solutions might be available. Essentially, when you have an Autosaving NSDocument that opens an NSWindow containing an NSToolbar the default 'Unified' toolbar style places the Document title to the left of the Toolbar. When the titlebar is laid out like this, there is a clickable area to the right of the title. If the user clicks in this area a log error appears that reads '[Document] Popover failed to show' This seems harmless enough, but in actual fact a memory leak has occurred with the 'NSDocumentTitlebarPopoverViewController' that has failed to show. This View Controller is retained, and unfortunately it contains a strong reference to the NSDocument. So the entire NSDocument instance is also retained. Here is a screenshot of the clickable area: Here is a link to a minimum reproducible example, hosted on GitHub. It is just a template Document Based App with an added Toolbar and a print statement in the Deinit of the Document so you can see if it deinits successfully. Searching online for the '[Document] Popover failed to show' log message doesn't yield any results, nor does searching for the leaking View Controller class name ('NSDocumentTitlebarPopoverViewController').
0
0
513
Oct ’23
Full Screen Cover and iPhone Orientation
Currently, there seems to be an all or nothing approach to supporting rotation on iPhone. Either every screen in your UI supports rotation, or none of them do. For a some apps however, that approach won't work. They have a number of screens that don't adapt well to a super letterboxed screen size, and a number of others that would benefit from the additional screen space. Previous discussion on this issue recommends the use of size classes, but this advice fails to recognise that some use cases simply aren't suited to being super letterboxed. Apple's own UI design is tacit acknowledgement of this: For example, the main UI of the Camera app stays fixed in the portrait orientation in the shooting mode, but presents a rotatable modal to review photos and videos. Even Springboard, the home screen of the iPhone, remains locked in the portrait orientation whilst allowing an app to be presented in landscape. Social media and news apps are another example: generally anchored around a portrait newsfeed that doesn't adapt well to extreme letterboxing, but surfacing rich media such as images, videos, charts and other interactive elements that could use the flexibility of landscape presentation. (News app, looking at you.) Is it time to re-visit the rotation characteristics of the phone vs. tablet idioms? Is this all-or-nothing approach to rotation serving the platform well? Regardless, app designers at Apple and elsewhere are creating apps that use this hybrid approach to rotation. And as things stand today, SwiftUI makes it very difficult. A rough equivalent can be made using a ZStack and observing the device orientation, but this requires hiding the status bar and provides no way to honor a user's portrait lock settings. The only other option, as far as I can tell, is building the app using UIKit view controllers, to thread through supportedInterfaceOrientations hooks. Personally, what I'd love to see is a new presentationInterfaceOrientations(_:) hook on View, that allows a fullScreenCover presentation to be specified as supporting an alternative orientation set. This could be iPhone only, and should serve the majority of use cases. However, in the meantime, it would be great to know if there's a technique that can get the UIKit behavior in a SwiftUI app that doesn't require rewriting the entire container view hierachy in UIKit.
0
1
624
Oct ’23
C# Cocoa app, button images stretched
Hi, One of my developers has upgraded their office Mac to Sonoma. The app we build has a WPF Windows UI layer, GTK for Linux and Cocoa for Mac, the code being written in C#. On Ventura, it builds and works fine. However, since he's upgraded his Mac to Sonoma, all the images on buttons are stretched to take up the whole size of the button, rather than the position stated, with text underneath. I can't share a screenshot here - it's an internal build not for customer or public use. The following mockups demonstrate what we're seeing: Code built on Sonoma Exact same code built on Ventura Any suggestions?
1
0
571
Oct ’23