Hi,
Inside a Mac Catalyst app, I need to display a popover starting from an NSToolbarItem contained inside the app toolbar (like the Apple Maps Mac app does, see below image).
In order to do that, when I press the button I need to find the toolbar item view and use it as popover anchor.
How can I find the view or frame of an NSToolbarItem on Mac Catalyst?
A property that could help me is the NSToolbarItem "view" property (NSView), but that property has been marked has unavailable in Mac Catalyst.
Any idea?
Thank you
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.
Post
Replies
Boosts
Views
Activity
I'm note sure if this is well-known-issue or not but it is very odd.
The problem can be reproduced with Apple's example code navigationBarItems(leading:trailing:)
As you can see, list separators has extra leading space that looks like they are indented for some reason.
I test above code with Playground, iPhone 13/15.3.1 they are the same.
I did messing around the code and found that applying .navigationBarTitle(), .navigationBarItems() to List causes the problem.
They must apply to each List item. Very odd though.
This means almost all List sample code that wrapping with NavigationView are WRONG.
Here is a fix I found.
Although I'm not sure if I can call this is a bug but definitely either document or implementation is wrong.
Could anyone explain this?
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
)
When marking the ViewController and the function with @MainActor, the assertion to check that the UI is updated on main thread fails.
How do I guarantee that a function is run on Main Thread when using @MainActor?
Example code:
import UIKit
@MainActor
class ViewController: UIViewController {
let updateObject = UpdateObject()
override func viewDidLoad() {
super.viewDidLoad()
updateObject.fetchSomeData { [weak self] _ in
self?.updateSomeUI()
}
}
@MainActor
func updateSomeUI() {
assert(Thread.isMainThread) // Assertion failed!
}
}
class UpdateObject {
func fetchSomeData(completion: @escaping (_ success: Bool) -> Void) {
DispatchQueue.global().async {
completion(true)
}
}
}
Even changing DispatchQueue.global().async to Task.detached does not work.
Tested with Xcode 13.2.1 and Xcode 13.3 RC
My application is currently crashing in production in iPhone devices running iOS 15.x. The app will work as normal while running developer mode, enterprise builds and Test Flight builds. Unfortunately, I am unable to reproduce this issue even app is downloaded from the app store.
I observed crash is happening at main.m.
Can someone help me to reproduce this issue?
How to read this crash log file?
Please find the crash log details attached.
2022-03-04_14-15-23.6227_+0900-a1899fd803a4ed683466702be71b9d224b4cd5bc.crash
I've been seeing this crash happening for a few years now. It's rare and unreproducible. The App's storyboard is large and it can occur on any segue and randomly it seems
Could not find a navigation controller for segue 'some-segue-on-storyboard'. Push segues can only be used when the source controller is managed by an instance of UINavigationController.
I've tried various things to prevent it. Double checked it was on the main thread to keep the UI happy and assumed all this time that it was just an iOS glitch/bug that Apple would get around to fixing.
That or it is a side effect of low memory.
Anyone got any suggestions for how to fix or what to investigate?
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?
Hi,
I thought this should be quite easy and maybe I only have tomatoes on my eyes, but I cannot find out how to call an action when the user clicks the red button or use CMD-W to close the Preferences window (= Settings Scene).
I use Core Data. In the Preferences, many data structures, which define my system, are changed.
I learned, that you shouldn't save too often to avoid performance problems, so now I want to save the Core Data context when the user closes the Preferences window.
I tried .onDisappear, onChange of focus etc. but this didn't work.
How can I define an action?
Any hints are welcome :-)
Hi,
I've implemented the FamilyActivityPicker and I also noticed that it is the same picker that we get when we go to Setttings > Screen Time > App Limits > Add Limit.
When you tap on a given row, it will present all apps that are in that category. If you press the check mark on Category then on the Category row will be updated by showing the checkmark as selected and a "All" text to the right side, and on the app rows from that category the check marks will also be marked as selected.
This behavior is not consistent when I implement the FamilyActivityPicker. If I go through the same process the app rows won't be shown as selected.
Any suggestions on how to make this work? I'm attaching screen shots to illustrate my point.
Settings App
My FamilyActivityPicker Implementation
Hello,
I just wanted to confirm that ScrollView and prefersDefaultFocus are currently not compatible, at least when building for tvOS
A simple example:
HStack {
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: true) {
VStack {
Button(action: {
resetFocus(in: namespace)
}) {
Text("RESET FOCUS")
}
HStack {
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], id: \.self) { v in
Button(action: {}) {
Text("ABC \(v)")
}.prefersDefaultFocus(v == 11, in: namespace)
}
}
}.onAppear {
resetFocus(in: namespace)
}
}
}
.focusScope(namespace)
}
}
On load of the view the focus remains on the first button in the HStack. On pressing the RESET FOCUS button focus is applied to the first button visible on the left side of the screen.
Am I missing something here? Is this the way these pieces of SwiftUI currently interact? e.g. prefersDefaultFocus has no effect inside a ScrollView?
Is there a way to focus a specific item in a ScrollView programmatically?
Thanks.
Hi dear , I am a beginner developer
I have an application idea , and I think its great idea 😎
I think the application needs to use Device activity frame work , and UIScreen class , even if the app is in background or terminated , the problem is I don't know how to use these classes and frameworks 🤷🏻♂️
the questions are :
can I detect UITouch event on UIScreen object even if the app is in background or terminated
How to get the current activity name of the device
I'm trying to add a quick look preview extension to my app.
But
I can't find any reference on this
On a earlier thread (https://developer.apple.com/forums/thread/704155)
everyone seems to misunderstand my question.
I MEAN THE QUICK LOOK YOU CAN TOGGLE IN FINDER THAT WILL SHOW YOU A PREVIEW OF A DOCUEMNT
I don't want to add the tag QuickLook because that's not I want to do.
Is there a way to optimize a List in SwiftUI?
There is a problem with selection not working properly when the List has many rows.
If you scroll to multi-select and up, some rows in the middle are not selected.
I have an issue where selecting an unselected row deselects nearby rows.
Is there any way for selection to work reliably even for a List of many rows?
I would like to find a solution that is stable even when multiple lines are selected, like mail and note, which are the default apps in ios.
ps. I am using CoreData.
@State var selectedItem = Set<MyEntity>()
List(selection: $selectItem){
ForEach(items, id: \.self){ item in
ContactsRow(contactsData: item)
}
}
.environment(\.editMode, $editMode)
In the recent WWDC 2022, FreeForm app was introduced and in that app in the tool picker there was a Fill Tool.
I want to put that fill tool (or any similar filling tool) in my xcode app that I am building. But when I use pencilkit PKToolPicker, there is not Fill Tool.
So how to get this fill tool in my app.
Any leads would be helpful. Thanks.
Overview
I am bit confused regarding drag and drop on SwiftUI
I think there are 2 approaches but I am stuck with both approaches
WWDC22
When using the new draggable, dropDestination, Transferable API, only single items are draggable. Multiple items in a list are not draggable. I have filed a feedback FB10128110
WWDC21
I have faced a couple of issues for drag and drop introduced in WWDC21 (onDrag, onDrop, itemIdentifier), the Feedback ids are FB9854301, FB9854569, FB9855245, FB9855532, FB9855567, FB9855575. It contains sample projects, would really appreciate if someone could have a look it.
Note: All feedbacks include a sample project with detail steps and some even have screenshots and videos
Questions:
If my approach is wrong or if I am missing something?
Unfortunately I didn't manage to get a SwiftUI lab session (got cancelled), so please help me with these issues.
After updating to NavigationStack with nested navigation links (with navigation links in a navigation destination), I see a lot of warnings in Xcode 14 beta:
Update NavigationAuthority bound path tried to update multiple times per frame.
Update NavigationAuthority possible destinations tried to update multiple times per frame.
The app often freezes when navigated with a NavigationLink. Do others see these problems?
Hi
I really liked the video by Paul Lettieri, creating a replacement for HStack that gives equal width to each, so I wrote one for my app. But the app doesn't compile for me. It gives me "Trailing closure passed to parameter of type 'HorizontalAlignment' that does not accept a closure" against the top VStack, not the place where the equal lengths HStack replacement appears.
This is my version of his struct:
extension LayoutSubviews {
func maxSize() -> CGSize {
let subviewSizes = map { $0.sizeThatFits(.unspecified) }
return subviewSizes.reduce(CGSize.zero) { CGSize(width: Swift.max($0.width, $1.width), height: Swift.max($0.height, $1.height)) }
}// maxSize()
func spacing() -> [Double] {
return indices.map { index in
guard index < count - 1 else { return 0.0 }
return self[index].spacing.distance(to: self[index + 1].spacing, along: .horizontal)
}
}// spacing()
}// extension LayoutSubviews
struct EqualWidthHStack: Layout {
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let maxsize = subviews.maxSize()
let totalSpacing = subviews.spacing().reduce(0) { $0 + $1 }
return CGSize(width: maxsize.width * Double(subviews.count) + totalSpacing, height: maxsize.height)
}// sizeThatFits
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let maxsize = subviews.maxSize()
let spacing = subviews.spacing()
let sizeProposal = ProposedViewSize(width: maxsize.width, height: maxsize.height)
var x = bounds.minX + maxsize.width / 2
for index in subviews.indices {
subviews[index].place(at: CGPoint(x: x, y: bounds.midX), anchor: .center, proposal: sizeProposal)
x += maxsize.width + spacing[index]
}
}// placeSubviews
}// EqualWidthHStack
I wrote this trivial View to test it:
struct ContentView: View {
var body: some View {
VStack {
HStack {
Button("Hi") { print("Hi!") }
Button("Hello") { print("Hello!") }
Button("Good evening") { print("Good evening!") }
}
EqualWidthHStack {
Button("Hi") { print("Hi!") }
Button("Hello") { print("Hello!") }
Button("Good evening") { print("Good evening!") }
}
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
}
}
I'm using Version 14.0 beta 2 (14A5229c) of Xcode. I was having a problem with the exact same message in another app with a much more complex main view.
I hope someone can tell me what to do or what is going on here.
Regards,
Mark
The Problem
In our brand new SwiftUI project (Multiplatform app for iPhone, iPad and Mac) we are using a ScrollView with both .horizontal and .vertical axes enabled. In the end it all looks like a spreadsheet.
Inside of ScrollView we are using LazyVStack with pinnedViews: [.sectionHeaders, .sectionFooters]. All Footer, Header and the content cells are wrapped into a LazyHStack each. The lazy stacks are needed due to performance reasones when rows and columns are growing.
And this exactly seems to be the problem. ScrollView produces a real layout mess when scrolling in both axes at the same time.
Tested Remedies
I tried several workarounds with no success.
We built our own lazy loading horizontal stack view which shows only the cells whose indexes are in the visible frame of the scrollview, and which sets dynamic calculated leading and trailing padding.
I tried the Introspect for SwiftUI packacke to set usesPredominantAxisScrolling for macOS and isDirectionalLockEnabled for iOS. None of this works as expected.
I also tried a workaround to manually lock one axis when the other one is scrolling. This works fine on iOS but it doesn't on macOS due to extreme poor performance (I think it's caused by the missing NSScrollViewDelegate and scroll events are being propagated via NotificationCenter).
Example Screen Recordings
To give you a better idea of what I mean, I have screenshots for both iOS and macOS.
Example Code
And this is the sample code used for the screenshots. So you can just create a new Multiplatform project and paste the code below in the ContentView.swift file. That's all.
import SwiftUI
let numberOfColums: Int = 150
let numberOfRows: Int = 350
struct ContentView: View {
var items: [[Item]] = {
var items: [[Item]] = [[]]
for rowIndex in 0..<numberOfRows {
var row: [Item] = []
for columnIndex in 0..<numberOfColums {
row.append(Item(column: columnIndex, row: rowIndex))
}
items.append(row)
}
return items
}()
var body: some View {
Group {
ScrollView([.horizontal, .vertical]) {
LazyVStack(alignment: .leading, spacing: 1, pinnedViews: [.sectionHeaders, .sectionFooters]) {
Section(header: Header()) {
ForEach(0..<items.count, id: \.self) { rowIndex in
let row = items[rowIndex]
LazyHStack(spacing: 1) {
ForEach(0..<row.count, id: \.self) { columnIndex in
Text("\(columnIndex):\(rowIndex)")
.frame(width: 100)
.padding()
.background(Color.gray.opacity(0.2))
}
}
}
}
}
}
.edgesIgnoringSafeArea([.top])
}
.padding(.top, 1)
}
}
struct Header: View {
var body: some View {
LazyHStack(spacing: 1) {
ForEach(0..<numberOfColums, id: \.self) { idx in
Text("Col \(idx)")
.frame(width: 100)
.padding()
.background(Color.gray)
}
Spacer()
}
}
}
struct Item: Hashable {
let id: String = UUID().uuidString
var column: Int
var row: Int
}
Can You Help?
Okay, long story short...
Does anybody knows a real working solution for this issue?
Is it a known SwiftUI ScrollView bug?
If there were a way to lock one scrolling direction while the other is scrolled, then I could deal with that. But at the moment, unfortunately, it is not usable for us.
So any solution is highly appreciated! Ideally an Apple engineer can help. 😃
NOTE: Unfortunately Apple does not allow URLs to anywhere. I also have two screen recordings for both iOS and macOS. So, if you would like to watch them, please contact me.
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)
}
}
Hi there,
In a SwiftUI View, I have a
@State var test: Double?
and a TextField like that :
TextField("Test", value: $test, formatter: NumberFormatter())
the variable test is constantly nil and never being populated with the Double value of the entered text.
Is it a bug or a concept error of mine ??
Thanks!