As someone who learned Swift via SwiftUI, UIKit is completely alien to me, so I apologize if this is actually a very simple issue.
I have a Messages extension that includes a sticker browser within it. In this extension, the MSMessagesAppViewController hosts a SwiftUI View, which in turn hosts a UIViewRepresentable version of MSStickerBrowserView.
The whole Messages App sheet moves with an upward drag, and can switch to its expanded mode, whenever the browser is scrolled to the top (first sticker is at top left), but it doesn't budge when the browser is scrolled to the other end when it should allow the sheet to move upward with the drag.
It seems something is reversed within the gesture priority management that allows a sheet to be moved in the appropriate direction when a contained scrollview is at the appropriate end.
Things I've tried while reaching a diagnosis include:
Limiting the presentation style to compact (the modal still moves, but never succeeds in changing)
Adding competing highPriorityGestures in the SwiftUI view, set at various locations
Inserting a rectangle with allowsHitTesting(false) beneath the browser
Changing firstResponder statuses for all relevant views
Changing GestureResponder priorities (there are no gesture responders in all views examined)
Things I've considered but don't have the technical skills to implement:
Have the view scroll a little downwards programmatically (like what can be done via ScrollViewReader in SwiftUI), but I have no idea how this can be done via MSStickerBrowserView or UIKit in general.
Maybe the MSStickerBrowserView thinks its always in the expanded state (when the sheet is expanded, the end-drags work fine). If this is the case, if there's a way to either fix this misconception (via controller's didTransition) or do away with end drags in general, the problem should go away.
Any pointers would be greatly appreciated!
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Post
Replies
Boosts
Views
Activity
Hello Dev,
Recently my client reported freezing the app screen when trying to dismiss it. Our application is related to music. When I checked the flow on the Simulator, I got the same case on the iPhone 15 series. I debugged the code and what I saw was CPU usage got 100% when I tried to pull down the model presented popover controller. I have checked the same flow multiple times and it worked 3-4 times and Additionally, it worked on some real devices and simulators too. So I can't understand what causing this issue.
Can you please help me on this? I'm looking forward to hearing from you.
Thank you in advance!
It looks like there's a new tab bar / column style design for tvOS that was introduced with the current TV app. Is there any word on this being a developer available component?
I have a SwiftUI view that works as expected in a full SwiftUI context. But I now need to use it in a UIViewController. It mostly works, but I'm trying to expose an @State var out to the viewController, and it only ever returns the initial value.
Any guidance for how best to pass out this @State var?
I could make it be a binding, but in my pure SwiftUI code, it works fine as @State (ie EditorView's container view does not need to know about sliderVal)
thanks, in advance, for any suggestions
import SwiftUI
import UIKit
class ViewController: UIViewController {
var host: UIHostingController<EditorView>?
override func viewDidLoad() {
super.viewDidLoad()
host = .init(rootView: EditorView())
guard let host = host else { return }
addChild(host)
host.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(host.view)
host.didMove(toParent: self)
}
@IBAction func helloTapped(sender: UIButton) {
guard let sliderValue = host?.rootView.sliderVal else { return }
print("UIKit sliderValue: \(sliderValue)")
}
}
struct EditorView: View {
@State var sliderVal: Double
init(sliderVal: Double? = nil) {
_sliderVal = State(initialValue: sliderVal ?? 7)
}
var body: some View {
VStack {
Slider(value: $sliderVal, in: 1...10)
Text("sliderVal: \(sliderVal)")
}
}
}
(NOTE: in order to see this code snippet in action you will need to create a button in the storyboard and link it to helloTapped)
import SwiftUI
import TipKit
struct ChatRoomView: View {
@StateObject private var socketManager = SocketIOManager()
@State private var inputText: String = ""
@StateObject var viewModel = SignInWithAppleViewModel()
@Binding var isCall: Bool
@State private var isSheet = false
@State private var ShowView = false
var learnlisttip = KeyTip()
@Binding var showShareSheet: Bool
@Binding var codeshar: String
var body: some View {
NavigationStack{
VStack {
if let roomCode = socketManager.roomCode {
ZStack{
VStack{
HStack{
Text("Room Key: \(roomCode)")
.font(.title)
.onAppear{
codeshar = roomCode
self.isCall = true
}
Button(action:{
self.showShareSheet = true
}, label:{
Image(systemName: "square.and.arrow.up.fill")
.accessibilityLabel("Share")
})
}
.padding(20)
TipView(learnlisttip, arrowEdge: .top)
.glassBackgroundEffect()
.offset(z: 20)
Spacer()
}
List(socketManager.messages, id: \.self) { message in
Text(message)
}
TextField("input", text: $inputText)
Button("send") {
socketManager.sendMessage(roomCode: roomCode, message: inputText)
inputText = ""
}
}
.sheet(isPresented: $showShareSheet) {
let shareContent = "Open SpatialCall, Join this Room, Key is: \(codeshar)"
ActivityView(activityItems: [shareContent])
}
} else {
HStack{
Button(action:{
withAnimation{
socketManager.createRoom()
}
}, label: {
VStack{
Image(systemName: "phone.circle.fill")
.symbolRenderingMode(.multicolor)
.symbolEffect(.appear, isActive: !ShowView)
.font(.largeTitle)
Text("Add Room")
.font(.title3)
}
})
.buttonStyle(.borderless)
.buttonBorderShape(.roundedRectangle)
.padding(.horizontal, 30)
.glassBackgroundEffect()
.offset(z: 20)
.scaleEffect(1.5)
.padding(60)
Button(action:{
withAnimation{
self.isSheet = true
}
}, label: {
VStack{
Image(systemName: "phone.badge.checkmark")
.symbolRenderingMode(.multicolor)
.symbolEffect(.appear, isActive:!ShowView)
.font(.largeTitle)
Text("Join Room")
.font(.title3)
}
})
.buttonStyle(.borderless)
.buttonBorderShape(.roundedRectangle)
.padding(.horizontal, 30)
.glassBackgroundEffect()
.offset(z: 20)
.scaleEffect(1.5)
.padding(70)
}
}
}
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
withAnimation {
self.ShowView = true
}
}
}
.sheet(isPresented: $isSheet){
VStack{
Text("Join Room")
.font(.largeTitle)
Text("You need to get the key to the room.")
TextField("Key", text: $inputText)
.padding(30)
.textFieldStyle(.roundedBorder)
Button(action:{
socketManager.joinRoom(roomCode: inputText)
self.isSheet = false
}, label: {
Text("Join Room")
.font(.title3)
})
.padding(50)
}
.padding()
}
.sheet(isPresented: $socketManager.showRoomNotFoundAlert) {
Text("The room does not exist. Please check whether the Key you entered is correct.")
.font(.title)
.frame(width: 500)
.padding()
Button(action:{
self.socketManager.showRoomNotFoundAlert = false
}, label: {
Text("OK")
.font(.title3)
})
.padding()
}
}
}
}
In the above code (this is a visionOS project), when I click Share, it can't display Sheet normally, and TipView can't be displayed either. Why?
In ios17 and above, I can detect when swiftUI app goes into and out of background using:
@Environment(\.scenePhase) private var phase
...
.onChange(of: phase) {
switch phase {
case .background:
print("entering background...")
case .active:
print("entering foreground...")
default: break
}
}
Is there a straightforward way to do this in SwiftUI for ios 16? I've found some examples using UIKit, but I am not that swift (sorry, couldn't resist) with that framework.
The app I work on has the Swift Language Version set to Swift 4.2 for the Compiler Language.
There has been some issues with users experiencing crashes due to UI changes not occurring on the main thread. I've been unable to reproduce the crash and using the Main Thread Checker has turned up nothing. So to fix this I assumed I could make the functions that are doing the navigating @MainActor functions, but that seems to have fixed nothing.
Xcode doesn't seem to have an issue with me including the @MainActor attribute on the functions, the build works and nothing seems amiss. But I'm wondering if because I'm compiling with Swift 4.2 (and I believe @MainActor was added in Swift 5.5), it's not actually using @MainActor attribute to ensure the code is run on the main thread?
I have been struggling with a crash bug that begin popping up in iPadOS 17 when we moved our app over to building under Xcode 15. It is important to note that the prior release, built under Xcode 14 works fine. Also, the crash does not occur in versions of iPadOS prior to iPadOS 17, even when built under Xcode 15.
The main view controller is a UISplitView that has primary, secondary, and supplemental views. Each, hosted in a UINavigationController. The primary view has the navigation bar hidden (this is important).
If the supplemental view has an additional view controller pushed onto the navigation stack, hence a back button is being shown in the middle navigation controller, and the app is transitioned to a compact size class (secondary controller shown at the top of the stack) and then transitions back to a regular size class, we get a crash with the following:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Layout requested for visible navigation bar, <UINavigationBar: 0x1038e3a40; frame = (0 -102; 834 102); opaque = NO; autoresize = W; gestureRecognizers = <NSArray: 0x600000d586f0>; layer = <CALayer: 0x6000003690e0>> delegate=0x105809800 standardAppearance=0x600002662940 scrollEdgeAppearance=0x600002661620, when the top item belongs to a different navigation bar. topItem = <UINavigationItem: 0x103b2bb10> titleView=0x1039b1a70 style=navigator rightBarButtonItems=0x6000000427e0 largeTitleDisplayMode=never searchController=0x1068c1a00 preferredSearchBarPlacement=stacked, navigation bar = <UINavigationBar: 0x103b452c0; frame = (0 24; 834 102); opaque = NO; autoresize = W; gestureRecognizers = <NSArray: 0x600000cd7d20>; layer = <CALayer: 0x600000316700>> delegate=0x104898400 standardAppearance=0x60000265ea00 scrollEdgeAppearance=0x60000265fd80, possibly from a client attempt to nest wrapped navigation controllers.'
*** First throw call stack:
(
0 CoreFoundation 0x0000000180491128 __exceptionPreprocess + 172
1 libobjc.A.dylib 0x000000018008412c objc_exception_throw + 56
2 Foundation 0x0000000180d1163c _userInfoForFileAndLine + 0
3 UIKitCore 0x00000001848d2510 -[UINavigationBar layoutSubviews] + 472
4 UIKitCore 0x0000000185806d78 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1492
5 UIKitCore 0x00000001848d21d8 -[UINavigationBar layoutSublayersOfLayer:] + 188
6 QuartzCore 0x0000000189ffa5b0 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 440
7 UIKitCore 0x00000001857f6260 -[UIView(Hierarchy) layoutBelowIfNeeded] + 292
8 UIKitCore 0x0000000184b147f8 -[UINavigationController _positionNavigationBarHidden:edge:initialOffset:] + 584
9 UIKitCore 0x0000000184b149b0 -[UINavigationController _positionNavigationBarHidden:edge:] + 264
10 UIKitCore 0x0000000184b163dc __64-[UINavigationController _setNavigationBarHidden:edge:duration:]_block_invoke + 404
11 UIKitCore 0x0000000184b1603c -[UINavigationController _setNavigationBarHidden:edge:duration:] + 488
12 UIKitCore 0x0000000184b14518 -[UINavigationController setNavigationBarHidden:animated:] + 92
However, if we do not hide the navigation bar in the primary view: no crash. Likewise, if there isn't a second controller pushed onto the navigation stack (meaning no back button is shown), there is no crash, even if the navigation bar is hidden in the primary view.
This structure has been fine for over three years and the problem only began with iPadOS 17 building under Xcode 15.
I have found similar mentions on other forums, but no real solution.
I realize I should probably file a feedback. Unfortunately, past experience has shown that it is a good way to waste countless hours gathering information, creating sample projects that distill the bugs down to their core, only to be met with complete and utter silence. I've lost all confidence in that system and I'm hoping someone else who has run into this may have a workaround or at least some suggestions for things to try.
Context: I maintain an app that has a UITabBarController at its root, and the tabs are UIHostingControllers to (mostly) SwiftUI views. I have a UINavigationController I present from that tab bar controller, and the rootViewController of that presented nav is a UIHostingController with SwiftUI views inside (not using NavigationView in there, but I am using .toolbar and NavigationLink).
I'm trying to use TipKit in this presented SwiftUI view, and its led to a couple unexpected issues:
When I dismiss a tip, the entire presented view controller hierarchy is dismissed (like calling window.rootViewController.dismiss())
somehow, configuring the tooltip inside of a ButtonStyle resolves this issue
When I show a tip pointing at a Button inside of the .toolbar
sometimes that tip is presented in the top left corner of the window, not pointing to the view properly
when the tip is dismissed, that button then stops calling its action and does nothing
Has anyone else experienced this/anything like it? Because of this (and other issues from the past) I get the sense that Apple is of the mind that you should either have a fully UIKit application, or a fully SwiftUI application, since issues with bridging between the two are not uncommon and solutions are unclear/undocumented. Curious what others think about this, and about maintaining UIKit/SwiftUI hybrid apps in general.
Hi,
I have used some custom Arabic fonts in UITextView to render some Arabic fonts.
On iOS 17 the following code is not giving me the correct position of the tapped text in some special cases.
Following the code i am using with the TapGestureRecognizer.
@objc func arabicTextViewTapped(_ sender: UITapGestureRecognizer) {
let attributedString = NSMutableAttributedString(attributedString: arabicTextView.attributedText)
attributedString.removeAttribute(.backgroundColor, range: NSRange(location: 0, length: attributedString.length))
let touchPosition = sender.location(in: sender.view)
guard let textPosition = arabicTextView.closestPosition(to: touchPosition),
let textRange = arabicTextView.tokenizer
.rangeEnclosingPosition(textPosition, with: .word, inDirection: .init(rawValue: 1)) else { return }
guard let text = arabicTextView.text(in: textRange) else { return }
}
In the image below
if there is some special character (called Ramos e aukaf) as the first character (which in this case is the small first character on the second line) then this code gives the position on the first line.
guard let textPosition = arabicTextView.closestPosition(to: touchPosition)
In the below case, the above code works perfectly fine as small character is not the first character on the second line. Also this is only happening on ios 17.
Any help is highly appriciated.
I have this Objective-C code that works well if placed inside viewDidAppear method - rotates view into the Portrait orientation;
UIWindowScene *windowScene = self.view.window.windowScene;
if (!windowScene) { return; }
UIWindowSceneGeometryPreferences *preferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:UIInterfaceOrientationMaskPortrait];
[windowScene requestGeometryUpdateWithPreferences:preferences errorHandler:^(NSError * _Nonnull error) {
// Handle error here
}];
Now I need to do that same rotation after user pressed Read button but before the selected document is loaded in another view. The problem - I can't figure out how to force view update after the code is executed. I see initial view rotated only after exiting that selected document, but I need it rotated before entering it.
Thank you
I want to use CUPS in iOS for printing and it is mentioned at many places that we can use cups for printing in ios .But when i import library cups/cups.h ,xcode is giving error "cups/cups.h not found".
code i am using in a objective c file :
import &lt;cups/cups.h&gt;
cups_dest_t *dest;
int num_options;
cups_option_t *options;
int job_id;
/* Print a single file */
job_id = cupsPrintFile(dest-&gt;name, "/usr/share/cups/data/testprint.ps",
"Test Print", num_options, options);
Do i need to intall some driver or any library to make it work ? or is it the case that CUPS is not available for iOS?
I am getting an error that crashes my app and takes me to AppDelegate file showing an error message
Thread 1: "Application tried to present modally a view controller <MyApp.CanvasViewController: 0x7fca1c70f610> that is already being presented by <UINavigationController: 0x7fca1d837800>
Basically what I was trying to do was to save an instance of UIViewController into app delegate protocol and then show every saved instance into a UITableView cell in which each cell will have a button to go back to that instance of the UIViewController.
@objc func actbuttonFuncCall(_ sender: UIButton) {
let index = sender.tag
// access the content of the singleton class where the struct.view: UIVIewController is saved
let identifier = VCs.shared.storedVc[index]?.view
let vc = identifier
print("tool bar button clicked! \(vc)")
vc?.modalPresentationStyle = .fullScreen
vc?.modalTransitionStyle = .coverVertical
// set main CanvasViewController as default value
present(vc ?? CanvasViewController(), animated: true)
}
That is to allow users to go back and forward into the main UIViewController where all the project functionality is executed. Is there anything I should consider doing to achieve my goal?
When a user updates their device to iOS 17 (any version) on a device with MDM, our app crashes but only on some device, not all. The same app runs fine on iOS 16. We cannot recreate the issue in-house and even our customers cannot reliably recreate the crash as it only happens on some devices and not others.
The crash we get is:
SIGABRT: UICollectionView internal inconsistency: missing final attributes for cell
Once the device gets this crash, the only way to fix it is to delete and reinstall the app and then everything works fine.
Anyone having a similar issue with iOS 17 and MDM?
I have collection view with hierarchical data source. Because of that, I create some cells with UICellAccessoryOutlineDisclosure accessory with style UICellAccessoryOutlineDisclosureStyleCell, so one can either tap on cell to open detail view or tap on outline disclosure accessory to reveal hidden child data.
Question:
How should I configure outline disclosure accessory to work with VoiceOver on?
It works fine without VoiceOver, but with VoiceOver it seems, that any gesture always leads to opening detail view.
I have four models: Vegetables, Fruits, Herbs and Condiments. Each model has separate collection view, and different cell identifier. Data is successfully fetched which I confirmed by printing number of objects.
I have used DiffableDataSource, where data source is initialized as follows:
Source & snapshot:
var dataSource: UICollectionViewDiffableDataSource<String, NSManagedObjectID>?
typealias DataSource = UICollectionViewDiffableDataSource<String, NSManagedObjectID>
typealias Snapshot = NSDiffableDataSourceSnapshot<String, NSManagedObjectID>
Setting up data source:
private func setupDataSource<T:NSManagedObject>(for collectionView:UICollectionView,
with identifier: String,
of entity: T.Type)
->DataSource
{
let dataSource = DataSource(
collectionView: collectionView,
cellProvider: {(collectionView, indexPath, managedObjectID) -> UICollectionViewCell? in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! KitchenCollectionViewCell
if let pantry = try? self.kitchenCoreDataStack.managedContext.existingObject(with: managedObjectID) as? T {
self.configure(cell: cell, for: pantry)
}
return cell
})
return dataSource
}
When breakpoint is set in above code, it doesn't go past this line:
cellProvider: {(collectionView, indexPath, manageObjectID)
Snapshot code to reflect changes:
extension KitchenViewController: NSFetchedResultsControllerDelegate{
func applySnapshot(animatingDifferences: Bool){
let snapshot = Snapshot()
dataSource?.apply(snapshot, animatingDifferences: animatingDifferences)
}
}
I called datasource function with :
dataSource = setupDataSource(for: firstCollectionView, with: "fruits", of: Fruits.self)
Hello everyone,
Is there a better solution than my approach out there to convert an image to data and back?
@Model
class User {
var name: String
@Attribute(.externalStorage) var image: Data?
var createdAt: Date
init(name: String, image: Data, createdAt: Date = .now) {
self.name = name
self.image = image
self.createdAt = createdAt
}
}
if let selectedPhotoData = imageData,
let uiImage = UIImage(data: selectedPhotoData) {
Image(uiImage: uiImage)
.resizable()
.scaledToFill()
.frame(width: 300, height: 300, alignment: .center)
.clipShape(Circle())
}
.task(id: selectedPhoto) {
if let data = try? await selectedPhoto?.loadTransferable(type: Data.self) {
imageData = data
}
}
I'm working on converting an app to SwiftUI, and I have a menu that used to be several table cells in a storyboard, but I moved it to an embedded SwiftUI view instead.
Here's the old way (from override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell ):
cellReuseID = "BillingToolsCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseID, for: indexPath)
if let billingToolsCell = cell as? BillingToolsCell {
billingToolsCell.billingToolsOptions.text = billingTools[indexPath.row].title
// Accessibility
billingToolsCell.isAccessibilityElement = true
billingToolsCell.accessibilityIdentifier = "Billing_\(billingTools[indexPath.row].title.replacingOccurrences(of: " ", with: ""))"
}
return cell
And here's the new way I'm creating the cell:
cellReuseID = "BillingToolsSwiftUI"
if let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseID, for: indexPath) as? SwiftUIHostTableViewCell<BillingToolsView> {
let view = BillingToolsView(billingToolVM: BillingToolViewModel()) { segueID in
self.performSegue(segueID: segueID)
}
cell.host(view, parent: self)
return cell
}
Here's the swiftUI view:
struct BillingToolsView: View {
@StateObject var billingToolVM: BillingToolViewModel
var navigationCallback: (String) -> Void
var body: some View {
VStack {
VStack{
ForEach(self.billingToolVM.billingToolList, id: \.self) { tool in
Button {
navigationCallback(tool.segueID)
} label: {
BillingToolsRowView(toolName: tool.title)
Divider().foregroundColor(AFINeutral800_SwiftUI)
}
.accessibilityIdentifier("Billing_\(tool.title.replacingOccurrences(of: " ", with: ""))")
}
}
.padding(.vertical)
.padding(.leading)
.background(AFINeutral0_SwiftUI)
}
}
}
If I check the accessibility inspector, I can see the identifier - here it is showing Billing_PaymentHistory:
But when the testers try to run their tests in Appium, they don't see any identifier at all:
Did I mess up setting up the accessibility identifier somehow? Or do the testers need to update their script?
Hello,
For the past month, I've been learning to use UIKit on Xcode to prepare for the Swift Student Challenge. However, I can't find a way to use my newly acquired skills in App Playgrounds. Do they strictly require SwiftUI? Is there a way to use UIKit and Storyboards?
Refer to ConferenceNewsFeedViewController in the attached project
Enable drag drop for collectionview
Increase the text/content in a few cells: refer ConferenceNewsController
Result: The cells behave weird: move up and down and shake , when trying to drag drop. This happens if the cell heights are not identical and if estimated values are used in compositional layout.
Anyone facing similar issues?