I've got a UIKit app and I want to add some buttons in a top-edge window ornament. I'm looking at the WWDC23 talk Meet UIKit for Spatial Computing, and it does exactly what I think I want to do:
extension EditorViewController {
func showEditingControlsOrnament() {
let ornament = UIHostingOrnament(sceneAlignment: .bottom, contentAlignment: .center) {
EditingControlsView(model: controlsViewModel)
.glassBackgroundEffect()
}
self.ornaments = [ornament]
editorView.style = .edgeToEdge
}
}
But the thing I really want to know is what is in EditingControlsView. Is it a toolbar? How do you make a toolbar in SwiftUI without something to attach the .toolbar modifier to?
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Post
Replies
Boosts
Views
Activity
I am trying to build a UICollectionView where the rows expand / collapse (for example, where the row only has a title initially, but when tapped expands to show a text view). I'm aware I can use UIContentConfiguration to swap a SwiftUI view for the cell's contentView, but I'm trying to do this in UIKit for configurability.
I have watched WWDC 22, 10068: What's new in UIKit, which made this sound easy...
I am using UICollectionLayoutListConfiguration for the UICollectionViewLayout.
When a cell is tapped, I update the subviews' constraints to the "expanded" state, but this just causes the subviews to expand beyond the cell height. All subviews are on cell.contentView. Calling layoutIfNeeded, invalidateIntrinsicContentSize, on cell doesn't change the cell height.
I assumed all I would need to do is set collectionView.selfSizingInvalidation = .enabledIncludingConstraints, but is overriding intrinsicContentSize of the cell the only way to accomplish this?
I'm developing Locked Camera Capture Extension.
I noticed UIViewController's view.frame size on extension is smaller than app's one. It seems extension's View.frame is same as safe-area's frame.
WWDC24 session Build a great Lock Screen camera capture experience doesn't mention this issue. It looks like bug for me or is it intended specification to avoid complexity for users ?
I'm developing LockedCameraCapture extension.
My extension can capture photo, save to system photo library and load from system photo library. That's pretty nice extension.
I want to fix interface orientation to portrait for particular screen(capture screen). But I want some other screen to landscape orientation(photo viewing screen).
So, I'm using "supportedInterfaceOrientations" property and "setNeedsUpdateOfSupportedInterfaceOrientations" method for interface orientation flexibility.
This code implies the screen only supports portrait orientation.
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
.portrait
}
And I call this code to enable orientation setting.
// UIViewController # viewDidLoad
setNeedsUpdateOfSupportedInterfaceOrientations()
My App work as expected, but my CaptureExtension doesn't work.
My extension's capture screen can rotate Landscape and that's not intended behavior.
New in iOS 17.5 is UIImpactFeedbackGenerator/impactOccurred(at:), which generates haptic feedback at a specific screen location.
https://developer.apple.com/documentation/uikit/uiimpactfeedbackgenerator/4403143-impactoccurred
Which devices support this?
How does this work if the Taptic Engine has a fixed physical location?
To set up iOS 18 widget tint mode without any modifications, follow the steps below.
I hope this helps many people.
You just need to add one line.
.containerBackgroundRemovable(false)
ex)
struct create_view: Widget {
let kind: String = "CalendarWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
calendar_widgetEntryView(entry: entry)
}
.supportedFamilies([.systemLarge])
.containerBackgroundRemovable(false)
.contentMarginsDisabledIfAvailable()
}
}
Before:
After :
Hi! I'm developing a custom keyboard and my user reported that they can't switch to my keyboard while using external original iPad keyboard.
Unfortunately, I can't test it on a real device and I can't find a way to test it using a simulator.
My questions:
Is it possible to simulate this case on a simulator?
Is it possible to temporarily show a custom keyboard while using an external keyboard on iPad? I saw in the photos that this keyboard has a globe button, but my user told me that nothing happens when they hold or press hit.
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Expected dequeued view to be returned to the collection view in preparation for display. When the collection view's data source is asked to provide a view for a given index path, ensure that a single view is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. For retrieving an existing view in the collection view, use -[UICollectionView cellForItemAtIndexPath:] or -[UICollectionView supplementaryViewForElementKind:atIndexPath:]. Dequeued view: <Pezzano_Enterprises.BannerImageCollectionViewCell: 0x103af8370; baseClass = UICollectionViewCell; frame = (880 0; 440 130); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x6000003980a0>>; Collection view: <UICollectionView: 0x106030c00; frame = (0 0; 440 130); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x600000de0240>; backgroundColor = <UIDynamicSystemColor: 0x6000017b0500; name = systemBackgroundColor>; layer = <CALayer: 0x600000337fe0>; contentOffset: {205.66666666666666, 0}; contentSize: {1320, 130}; adjustedContentInset: {0, 0, 0, 0}; layout: <UICollectionViewFlowLayout: 0x103b35720>; dataSource: <Pezzano_Enterprises.BannerTableViewCell: 0x10605d000; baseClass = UITableViewCell; frame = (0 0; 440 130); autoresize = W; layer = <CALayer: 0x600000336900>>>'
Hello everyone !
We've observed with our team that the default value of the modalPresentationStyle for an UIViewController has changed on iOS 18/XCode 16.
We've made a small playground to test it
import UIKit
var navigationController = UINavigationController()
navigationController.modalPresentationStyle = .automatic
navigationController.modalPresentationStyle.rawValue
The rawValue of the modalPresentationStyle on XCode 15 was 1, so the value of .pageSheet, which is okay since it is the default value specified in the documentation.
Since Xcode 16 this value has changed to 2 which is the value of .formSheet.
Did this change in particular has been specified anywhere by Apple ? The closest thing I've been able to find is the new .presentationSizingfor sheets in SwiftUI but I have not found anything for UIKit.
Thank you very much for your time !
I have an app that is pretty simple and allows information to be collected when offline. The app works perfectly while online where users can type into textfields. However when cellular and WiFi is disabled, tapping into the textfield displays the on-screen keyboard. As soon as this appears, the app enters a system hang and no typing or any user interaction is possible.
Upon profiling, it appears that this has to do with an infinite loop with the keyboard detecting a change in the network for dictation and then trying to load an image asset, presumably the dictation button. The keyboard will not contain this button either. This is on a regular UITextField with no delegate or special treatment. I have removed all "appearance" in the app and that makes no difference.
This seems to be a major bug in iOS 17 and higher. It continues to fail on iOS 18+ as well as new versions of Xcode, updated SDKs, etc.
I can do this in other apps I've developed without issue so I'm assuming there's something in the app that is interfering somehow with the dictation network connectivity in the keyboard. Either way, an app interfering with the keyboard function still seems like a possible flaw in the operating system.
There are also multiple warnings displayed in the console in Xcode about AFPreferences unable to resolve system language too. This fills up the console very quickly because of the looping nature of this asset layout issue. Because this is never completing and getting locked up, you'll notice that the dictation button does not appear in the lower right corner. However the cursor continues to blink but the user interface is non-responsive.
Any ideas what would be interfering with the drawing of the keyboard like this?
When I create a modal segue to a navigation controller in a storyboard, the navigation bar buttons appear correctly. But when trying to recreate this programmatically, no buttons appear:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .infoLight, primaryAction: UIAction(handler: { _ in
self.present(UINavigationController(rootViewController: ModalViewController()), animated: true)
}))
button.frame.origin = CGPoint(x: 100, y: 100)
view.addSubview(button)
}
}
class ModalViewController: UIViewController {
override func loadView() {
let button = UIBarButtonItem(title: "button")
button.primaryAction = UIAction(handler: { action in
})
button.style = .done
navigationItem.title = "title"
navigationItem.rightBarButtonItem = button
view = UITableView()
}
}
What am I doing wrong?
You used to be able to use the "User Defined Runtime Attributes" section in Interface Builder to add attributes such as layer.borderColor, layer.borderWidth, layer.cornerRadius, etc. I can still enter these values, but they don't do anything. What happened?
I can still set them via code and then they work, but it's much more convenient to be able to do it in interface builder.
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?
I'm embedding PHPickerViewController in my application with a little bit of other chrome around it to provider context about how to upload.
But the fact that the controller has a translucent background to the videos when scrolling, and the rest of my UI doesn't, looks bad. Is there a way to customize the controller to either:
have the translucent background extend further than the extents of it, or
remove the translucent background entirely?
Below iOS, 18.0 its working properly but in iOS 18.0 facing issue
I can download pdf , I can see downloaded pdf in app sandbox container but unable to preview with app
I was trying to show my nextKeyboardButton based on the value of needsInputModeSwitchKey when the viewDidLoad or viewWillAppear.
nextKeyboardButton.isHidden = !self.needsInputModeSwitchKey
However, my Xcode console always showed this error when I call the key at viewDidLoad, viewWillAppear, viewWillLayoutSubviews and viewDidLayoutSubviews.
2024-10-15 11:50:34.306515+0800 MyKeyboard[6040:25025964] [External] -[UIInputViewController needsInputModeSwitchKey] was called before a connection was established to the host application. This will produce an inaccurate result. Please make sure to call this after your primary view controller has been initialized.
The timing of connection was established to the host application. probably not related to the life cycle of extension? What's the right way use this key without warning?
Input issues occur in the textField while using a bilingual keyboard (Korean and English).
System settings:
Keyboard: Bilingual (Korean & English)
Project environment:
Xcode >= 15.4 & iOS >= 18.0
Base localization: Korean
// UITextField settings:
textField.keyboardType = .decimalPad // or .phonePad
self.textField.addTarget(self, action: #selector(self.textFieldEditingChanged), for: .editingChanged)
@objc
func textFieldEditingChanged() {
self.textField.text = "\(self.textField.text!)-"
}
/*
Input: 123456
Expected: 1-2-3-4-5-6-
Result: 11111123456-
*/
The issue occurs when modifying the text of the textField in the editingChanged event.
In the above code, a hyphen is appended to the input with each character.
When typing 123456, the expected result is:
Input: 1 → Result: 1-
Input: 2 → Result: 1-2-
…
Input: 6 → Result: 1-2-3-4-5-6-
However, the actual result is 11111123456-.
Another example:
@objc
func textFieldEditingChanged() {
print("before", self.textField.text!)
self.textField.text = self.textField.text?.replacingOccurrences(of: "0", with: "1")
print("after", self.textField.text!)
}
When inputting 0 1 0 sequentially, the output is:
before 0 after 1
before 01 after 11
before 010 after 111
The value of "after" matches expectations,
but the "before" value reverts to 0 on the next input, even though it appears as 1 on the UI.
When the bilingual keyboard option is turned off or the base localization is set to something other than Korea, the issue does not occur.
Could you provide information on whether this issue will be resolved in the next iOS version, or if there is a workaround?
In iOS, when using a UICollectionView with horizontal scrolling and only one row of cells: if all the cells have the same width, the spacing between cells is determined by minimumLineSpacing. If the cell widths are different, the spacing between cells is controlled by minimumInteritemSpacing. However, when the cell widths are different and the collectionView's height is smaller than the height of the cells, the minimumInteritemSpacing is applied to the left side of the first cell, causing the left margin of the first cell to become wider. Why does this happen?
iOS 18 introduced the elevated tab bar for iPad devices. However, the tint color for UITabBar items is not changing. Adjusting the barTintColor and tintColor properties of the tab bar items does not seem to have any effect.
I have a UITableView which contains a UICollectionView in the first row. It used to work fine in iOS17, but now I get a crash when running with Xcode 16 / iOS18 beta:
Expected dequeued view to be returned to the collection view in preparation for display. When the collection view's data source is asked to provide a view for a given index path, ensure that a single view is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. For retrieving an existing view in the collection view, use -[UICollectionView cellForItemAtIndexPath:] or -[UICollectionView supplementaryViewForElementKind:atIndexPath:]
This is my UITableView delegate call:
AddEditDataCell *cell = nil;
if (indexPath.section == 0) {
if (indexPath.row == 0) {
AddEditDataContactsCell *contactNameCell = (AddEditDataContactsCell *)[self cellForContactNamesCollectionAtIndexPath:indexPath tableView:tableView];
return contactNameCell;
- (AddEditDataContactsCell *)cellForContactNamesCollectionAtIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableView {
AddEditDataContactsCell *contactsCell = (AddEditDataContactsCell *)[self.tableView dequeueReusableCellWithIdentifier:@"ContactsCell" forIndexPath:indexPath];
if (self.collectionNameCell == nil) {
self.collectionNameCell = [contactsCell.collectionView dequeueReusableCellWithReuseIdentifier:@"LogContactNameCollectionCellIdentifier" forIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
contactsCell.nameCellDelegate = self;
}
contactsCell.frame = CGRectZero;
[contactsCell setNeedsLayout];
[contactsCell.collectionView reloadData];
contactsCell.collectionViewHeightConstraint.constant = contactsCell.collectionView.collectionViewLayout.collectionViewContentSize.height;
[contactsCell.collectionView.collectionViewLayout invalidateLayout];
return contactsCell;
}