Post

Replies

Boosts

Views

Activity

Displaying limited contacts list in UIKit
I have an app that was written in UIKit. It's too large, and it would be much too time consuming at this point to convert it to SwiftUI. I want to incorporate the new limited contacts into this app. The way it's currently written everything works fine except for showing the limited contacts in the contact picker. I have downloaded and gone though the Apple tutorial app but I'm having trouble thinking it through into UIKit. After a couple of hours I decided I need help. I understand I need to pull the contact IDs of the contacts that are in the limited contacts list. Not sure how to do that or how to get it to display in the picker. Any help would be greatly appreciated. func requestAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void) { switch CNContactStore.authorizationStatus(for: .contacts) { case .authorized: completionHandler(true) case .denied: showSettingsAlert(completionHandler) case .restricted, .notDetermined: CNContactStore().requestAccess(for: .contacts) { granted, error in if granted { completionHandler(true) } else { DispatchQueue.main.async { [weak self] in self?.showSettingsAlert(completionHandler) } } } // iOS 18 only case .limited: completionHandler(true) @unknown default: break } } // A text field that displays the name of the chosen contact @IBAction func contact_Fld_Tapped(_ sender: TextField_Designable) { sender.resignFirstResponder() // The contact ID that is saved to the Db getTheCurrentContactID() let theAlert = UIAlertController(title: K.Titles.chooseAContact, message: nil, preferredStyle: .actionSheet) // Create a new contact let addContact = UIAlertAction(title: K.Titles.newContact, style: .default) { [weak self] _ in self?.requestAccess { _ in let openContact = CNContact() let vc = CNContactViewController(forNewContact: openContact) vc.delegate = self // this delegate CNContactViewControllerDelegate DispatchQueue.main.async { self?.present(UINavigationController(rootViewController: vc), animated: true) } } } let getContact = UIAlertAction(title: K.Titles.fromContacts, style: .default) { [weak self] _ in self?.requestAccess { _ in self?.contactPicker.delegate = self DispatchQueue.main.async { self?.present(self!.contactPicker, animated: true) } } } let editBtn = UIAlertAction(title: K.Titles.editContact, style: .default) { [weak self] _ in self?.requestAccess { _ in let store = CNContactStore() var vc = CNContactViewController() do { let descriptor = CNContactViewController.descriptorForRequiredKeys() let editContact = try store.unifiedContact(withIdentifier: self!.oldContactID, keysToFetch: [descriptor]) vc = CNContactViewController(for: editContact) } catch { print("Getting contact to edit failed: \(self!.VC_String) \(error)") } vc.delegate = self // delegate for CNContactViewControllerDelegate self?.navigationController?.isNavigationBarHidden = false self?.navigationController?.navigationItem.hidesBackButton = false self?.navigationController?.pushViewController(vc, animated: true) } } let cancel = UIAlertAction(title: K.Titles.cancel, style: .cancel) { _ in } if oldContactID.isEmpty { editBtn.isEnabled = false } theAlert.addAction(getContact) // Select from contacts theAlert.addAction(addContact) // Create new contact theAlert.addAction(editBtn) // Edit this contact theAlert.addAction(cancel) let popOver = theAlert.popoverPresentationController popOver?.sourceView = sender popOver?.sourceRect = sender.bounds popOver?.permittedArrowDirections = .any present(theAlert,animated: true) } func requestAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void) { switch CNContactStore.authorizationStatus(for: .contacts) { case .authorized: completionHandler(true) case .denied: showSettingsAlert(completionHandler) case .restricted, .notDetermined: CNContactStore().requestAccess(for: .contacts) { granted, error in if granted { completionHandler(true) } else { DispatchQueue.main.async { [weak self] in self?.showSettingsAlert(completionHandler) } } } // iOS 18 only case .limited: completionHandler(true) @unknown default: break } } // MARK: - Contact Picker Delegate extension AddEdit_Quote_VC: CNContactPickerDelegate { func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) { selectedContactID = contact.identifier let company: String = contact.organizationName let companyText = company == "" ? K.Titles.noCompanyName : contact.organizationName contactNameFld_Outlet.text = CNContactFormatter.string(from: contact, style: .fullName)! companyFld_Outlet.text = companyText save_Array[0] = K.AppFacing.true_App setSaveBtn_AEQuote() } } extension AddEdit_Quote_VC: CNContactViewControllerDelegate { func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool { return false } func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) { selectedContactID = contact?.identifier ?? "" if selectedContactID != "" { let company: String = contact?.organizationName ?? "" let companyText = company == "" ? K.Titles.noCompanyName : contact!.organizationName contactNameFld_Outlet.text = CNContactFormatter.string(from: contact!, style: .fullName) companyFld_Outlet.text = companyText getTheCurrentContactID() if selectedContactID != oldContactID { save_Array[0] = K.AppFacing.true_App setSaveBtn_AEQuote() } } dismiss(animated: true, completion: nil) } }
1
0
308
Sep ’24
Convert from SQLite database in UIKit to storage on iCloud
My apps are set up to store data in a SQLite database on the device. The user is also able to add images and those are also stored on the device. The database and images are stored in the apps documents folder. The database is set up with four tables, one of them containing a list of selectable items so the information in that table is constant. The other three are read/write to the user. The database also contains a field, which contains true/false as to whether the app has been purchased or not. My thought behind was that this would make the users data private and secure. My apps are set up using UIKit so SwiftData is not an option unless I rewrite the entire app in SwiftUI. Or is there a good way to use SwiftData in UIKit? Is there a way to store/move this information into the cloud so that the data can be synced across multiple devices? Or maybe set up an import/export scenario using a CSV file for the database using Dropbox? Any help or advice would be appreciated. Thanks in advance.
0
0
476
Feb ’24
Apps not showing metrics in analytics on App Store Connect
On Jan 2, 2024 I uploaded and got released 13 new apps. The problem I'm having is that only one of the new apps is showing data in analytics, the other 12 show nothing. They are all very similar apps with pretty much the same search criteria as the rest of my apps, 42 total. All of the other apps show plenty of analytic data. I've done searches and the apps do show up in the search. Is there a limit on the number of apps you can have? Is there a way to have Apple look and see if I've done something wrong that's causing the problem? Thank in advance
0
0
390
Feb ’24
How to reconnect the Info.plist to the Build Settings
I'm working on some older apps, and I don't think they were ever opened in Xcode 14. I'm updating them in Xcode 15 and I'm having some problems with the Plist. It looks like I've lost the link between the Info.plist and their related Build Settings. I want to lock the iPhone orientation to portrait. This always worked in the past. When I change the Deployment Info, iPad Orientations or iPhone Orientations using the checkboxes the updates show up in the Info Custom iOS Target Properties (info.plist). However, they are not reflected in the Info.plist Values in the build settings. Even if I update the build settings manually, I still don't have the iPhone locked in portrait orientation. Has anybody run into this and know how to fix it? Thanks for the help in advance.
0
0
376
Oct ’23
Configuring button attributes - Xcode 15, iOS 17
I'm updating my apps to iOS 17 and in Xcode 14 this code worked perfectly. However, Xcode 15 decided it wasn't going to let it work anymore. What I want to accomplish is to set the title of the button to be white and the icon to be blue. In other words, I want to control the color of both items separately. I'd also like to know how to set the disabled color of the button using configurations. I've tried using baseBackgroundColor and baseForegroundColor but it doesn't seem to make any difference. In interface builder, the button is bone stock with no attributes except the title text. (system, plain, plain) I've tried .plain(), .tinted(), .borderless() and commenting the line out but noting gives me what I need. Any help would be greatly appreciated. ` extension UIButton { func settingsBtn_Attributes() { self.configuration = .plain() self.configuration?.image = UIImage(systemName: K.Icons.settings, withConfiguration: UIImage.SymbolConfiguration(scale: .large)) self.configuration?.title = K.Tabbar_Names.settings self.configuration?.attributedTitle?.foregroundColor = .white self.configuration?.imagePlacement = .top self.configuration?.titleAlignment = .center self.configuration?.imagePadding = 6 self.configuration?.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0) self.configuration?.attributedTitle?.font = .systemFont(ofSize: gMenuTextSize, weight: .regular) } }`
1
0
1.1k
Oct ’23
Multiple In-App Purchases - Non-Consumable
I have a question regarding multiple in-app purchases. I want to release my app with one in-app purchase however, I want to add two more at a later release. Currently I have all three in-app purchases set up in the app, but only one is set on the prepare for submission screen under In-App Purchases and Subscriptions. My question is, are these additional in-app purchases going to cause a problem with my initial release? Should I delete them and just add them later with the next rev?
1
0
444
Sep ’23
Commit window not showing changed files, BitBucket
I had an ugly glitch when I was committing one of my Xcode projects to BitBucket. I thought it was just a wifi connection issue but there's something else going on. I've tried to commit several other projects and they are all exhibiting the same problem. I have attached a screen-shot of the window that opens when doing a commit. There are files that have been changed but they do not show in the commit window. I don't see any Xcode settings that were changed. I have deleted and reinstalled Xcode and it didn't change anything. Has anybody experienced this?
0
0
440
May ’23
In-App Purchase Restore - No observers found
When I execute a restore on my in-app purchase I'm getting a warning, however the restore is successfully executed. I think this is something new with Xcode 14.3. My test device is running iOS 16.4 This is the warning: <SKPaymentQueue: 0x283708a80>: No observers found that respond to "paymentQueue:shouldAddStorePayment:forProduct:", will not check for purchase intents It fires at this point in the code. If I comment out the first line, I don't get the warning however, the restore doesn't execute. Is anybody else seeing this or do I have something wrong in my code? I know it's only a warning but any help would be appreciated. @IBAction func restoreButtonTapped(_ sender: UIBarButtonItem) { SKPaymentQueue.default().add(self) SKPaymentQueue.default().restoreCompletedTransactions() } I've included the rest of the code just for a completeness. func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { switch transaction.transactionState { case .purchasing: //print("Purchase in progress...") break case .purchased: //print("Purchase Successful") SKPaymentQueue.default().finishTransaction(transaction) //print("Transaction Complete") // Hide the restore button navigationItem.setRightBarButton(nil, animated: true) //Set the BaseVerion in the Db to true IAPHandler.set_BaseVersion_To_Purchased() //Also hide the Purchase button UIView.animate(withDuration: 1.0, animations: { [weak self] in self?.purchaseButton.alpha = 0 }) { [weak self] (success) in self?.selector_Top_Constraint.constant = 30 } case .failed: if let error = transaction.error { let errorDescription = error.localizedDescription print("Transaction failed due to error: \(errorDescription)") } case .restored: SKPaymentQueue.default().finishTransaction(transaction) //print("Transaction Complete") // Hide the restore button navigationItem.setRightBarButton(nil, animated: true) // Set the BaseVerion in the Db to true IAPHandler.set_BaseVersion_To_Purchased() // Also hide the Purchase button UIView.animate(withDuration: 1.0, animations: { [weak self] in self?.purchaseButton.alpha = 0 }) { [weak self] (success) in self?.selector_Top_Constraint.constant = 30 } case .deferred: //print("Purchase Deferred") break @unknown default: if let error = transaction.error { let errorDescription = error.localizedDescription print("Transaction failed due to error: \(errorDescription)") } break } } } @IBAction func purchaseButtonTapped(_ sender: UIButton) { let theAlert = UIAlertController.init(title: K.Titles.pleaseChoose, message: nil, preferredStyle: .actionSheet) let theCancleAction = UIAlertAction(title: K.Titles.cancel, style: .cancel) let thePurchaseAction = UIAlertAction(title: K.DefaultList_Buttons.purchase_BaseVersion_Btn, style: .default) { [weak self] (action2) in if SKPaymentQueue.canMakePayments() { // User can make payments let paymentRequest = SKMutablePayment() paymentRequest.productIdentifier = self!.base_Product_ID SKPaymentQueue.default().add(self!) SKPaymentQueue.default().add(paymentRequest) } else { // User cannot make payments print("User cannot make payments") } } theAlert.addAction(thePurchaseAction) theAlert.addAction(theCancleAction) theAlert.setValue(NSAttributedString(string: theAlert.title ?? "", attributes: [.font : UIFont.systemFont(ofSize: (gDefaultTextSize - 2), weight: UIFont.Weight.semibold)]), forKey: "attributedTitle") let popOver = theAlert.popoverPresentationController popOver?.sourceView = sender popOver?.sourceRect = sender.bounds popOver?.permittedArrowDirections = .any present(theAlert, animated: true) }
5
3
5.6k
Apr ’23
Setting a field that is populated by a stepper to have a trailing 0
I my app I have four steppers and each has a related field. I have the stepValue of each stepper set to 0.1. The associated fields are editable, and I have them set to have a trailing 0 when editing ends. Everything works fine. The stepper increments at 0.1 and populates the field. When the field edited ends it has a trailing 0. The problem is that the stepper does not have a trailing zero on the whole number. So, with the stepper, I get 0.8, 0.9, and then 1 with no training 0, hen 1.1. How can I make sure I have a trailing 0 with the whole numbers? @IBAction func editing_Ended_Flds(_ sender: UITextField) { let stringValue: String = sender.text ?? "" if let value = Double(stringValue) { sender.text = "\(String(format: "%.1f", value))" } } @IBAction func editingChanged_Flds(_ sender: UITextField) { switch sender { case fade_In_Fld_Outlet: fade_In_stepper_Outlet.value = Double(sender.text!) ?? 0.0 case fade_Out_Fld_Outlet: fade_Out_stepper_Outlet.value = Double(sender.text!) ?? 0.0 case pause_Before_Fld_Outlet: pause_Before_stepper_Outlet.value = Double(sender.text!) ?? 0.0 case pause_After_Fld_Outlet: pause_After_stepper_Outlet.value = Double(sender.text!) ?? 0.0 default: break } } @IBAction func stepper_Tapped(_ sender: UIStepper) { switch sender { case fade_In_stepper_Outlet: fade_In_Fld_Outlet.text = Double(sender.value).formatted() case fade_Out_stepper_Outlet: fade_Out_Fld_Outlet.text = Double(sender.value).formatted() case pause_Before_stepper_Outlet: pause_Before_Fld_Outlet.text = Double(sender.value).formatted() case pause_After_stepper_Outlet: pause_After_Fld_Outlet.text = Double(sender.value).formatted() default: break } }
1
0
442
Apr ’23
Configuring the highlight of a list collectionView cell
In a collection view I want that when a cell is tapped to have the background color changed to indicate highlighting. When that same cell is tapped again, turn the highlighting off. When another cell is tapped, un-highlight the previously highlighted cell and highlight the new one. I pretty much have that working but it's all done manually in code. If there's a better way using delegate methods or something, please enlighten me. The collection view is in a pop-up view. My problem is that when the pop-up view is closed and then reopened, the last selected cell is still highlighted. I tried this, but no-joy. choose_CollectionView_Outlet.indexPathsForSelectedItems?.forEach { choose_CollectionView_Outlet.deselectItem(at: $0, animated: false) } I think it's because I am manually setting the background color to indicate highlight. If anybody has a solution for this, please share it. extension Choose_Items_VC: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if collectionView == collectionView_Outlet { // Filter Selection let item = itemArray[indexPath.row].Item_Name if let cell = collectionView.cellForItem(at: indexPath) { cell.backgroundColor = .lightGray } switch itemPicked { case K.AppFacing.type: if item == type_Fld_Outlet.text { pickerDoneBtn_Outlet.isEnabled = false pickerFld_Outlet.text = "" newType_ID = 0 } else { pickerFld_Outlet.text = item newType_ID = itemArray[indexPath.row].ItemID pickerDoneBtn_Outlet.isEnabled = true } case K.AppFacing.style: if item == style_Fld_Outlet.text { pickerDoneBtn_Outlet.isEnabled = false pickerFld_Outlet.text = "" newType_ID = 0 } else { pickerFld_Outlet.text = item newType_ID = itemArray[indexPath.row].ItemID pickerDoneBtn_Outlet.isEnabled = true } case K.AppFacing.venue: if item == venue_Fld_Outlet.text { pickerDoneBtn_Outlet.isEnabled = false pickerFld_Outlet.text = "" newType_ID = 0 } else { pickerFld_Outlet.text = item newType_ID = itemArray[indexPath.row].ItemID pickerDoneBtn_Outlet.isEnabled = true } default: break } } else if collectionView == choose_CollectionView_Outlet { let cell = collectionView.cellForItem(at: indexPath) if cell?.backgroundColor == .lightGray { cell?.backgroundColor = nil // cell?.isSelected = false // cell?.isHighlighted = false add_Btn_Outlet.isEnabled = false gItem_ID = 0 } else { cell?.backgroundColor = .lightGray // cell?.isSelected = true // cell?.isHighlighted = true gItem_ID = choose_Items_Array[indexPath.item].ItemID add_Btn_Outlet.isEnabled = true } } } func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) { if let cell = collectionView.cellForItem(at: indexPath) { if collectionView == collectionView_Outlet { cell.backgroundColor = .lightGray } } } func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) { if let cell = collectionView.cellForItem(at: indexPath) { if collectionView == collectionView_Outlet { cell.backgroundColor = nil } } } func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) { if let cell = collectionView.cellForItem(at: indexPath) { cell.backgroundColor = nil } } }
0
0
571
Apr ’23
Controlling what happens when the view background is tapped
I'm trying to control what happens when the view background is tapped. The view has a field, a button and a list collectionView. When the user enters a name into the field, the button is enabled and when the button is tapped the name from the field is saved into a list collectionView. What I want to happen: If the field isFirstResponder when the viewBackGround is tapped then I want the superView_Tapped() to be triggered. If the collectionView is tapped it works fine. If the view background is tapped it works fine. When the view backGround is tapped the field text is cleared and sone other things take place. See superView_Tapped() below. What actually happens: The problem I'm having is that tapping the button also triggers the superView_Tapped(). So what happens is the field is emptied and a row is inserted into the collection view with no name. The part of the reason is that the superView_Tapped() is fired first and then the button code fires after. Is there a way to exclude the button tap from triggering the superView_Tapped()? let tap = UITapGestureRecognizer(target: self, action: #selector(self.superView_Tapped)) tap.numberOfTapsRequired = 1 tap.delegate = self tap.cancelsTouchesInView = false self.view.addGestureRecognizer(tap) @objc func superView_Tapped() { if insertFld.isFirstResponder { insertFld.resignFirstResponder() insertFld.text = "" insertButton.isEnabled = false // print("They emptied the fld when editing", gItemID) gItemID = 0 insertButton.filled_Red_Back(title: K.Titles.add_Btn) theOriginal_Text = "" } } @IBAction func insertButton_Tapped(_ sender: UIButton) { if current_Item_ID != 0 { update() } else { insertRow() } } func update() { let theItemName = insertFld.text do { try dbQueue_GRDB.write { db in try db.execute(sql: "UPDATE " + theTable + " SET Item_Name = :item_Name WHERE ItemID = :id", arguments: ["item_Name": theItemName, "id": current_Item_ID]) } applySnapshot() clean_Up() if ModelData.getTheConfirmation_Bool() { sendConfirmationAlert(theTitle: "Updated", theMessage: nil, buttonTitle: K.Titles.ok) } } catch { let theString = "\(error)" if theString.contains("UNIQUE constraint failed") { sendConfirmationAlert(theTitle: K.Titles.itemAlreadyExists, theMessage: nil, buttonTitle: K.Titles.ok) } else { print("Updating list failed! \(VC_String) \(error)") } } } func insertRow() { let insertName = insertFld.text?.trimmingCharacters(in: .whitespaces) do { try dbQueue_GRDB.write { db in try db.execute(sql: "INSERT INTO " + theTable + " (Item_Name,Practice,Training,Practice_Log) VALUES (?,?,?,?)", arguments: [insertName,"false","",""]) } if ModelData.getTheConfirmation_Bool() { sendConfirmationAlert(theTitle: "Row Created", theMessage: nil, buttonTitle: K.Titles.ok) } applySnapshot() clean_Up() } catch { let theString = "\(error)" if theString.contains("UNIQUE constraint failed") { sendConfirmationAlert(theTitle: K.Titles.itemAlreadyExists, theMessage: nil, buttonTitle: K.Titles.ok) } else { print("Inserting to list failed! \(VC_String) \(error)") } } }
2
0
802
Jan ’23
Something broke from Xcode 14.1 to Xcode 14.2 keyboardFrameWillChange
This is regarding the keyboardFrameWillChange notification. This code worked as expected under Xcode 14.1 With floating_Keyboard = false Tap the textView Full keyboard opens textView moves up to avoid the keyboard Change to floating keyboard Floating keyboard opens textView moves to home position Tap the view background to close the keyboard Tap the textView again Floating keyboard opens txtView remains at home position Change to full keyboard Full keyboard opens textView moves up to avoid the keyboard With Xcode 14.2 if the keyboard is floating and the textView is firstResponder, and the keyboard is then set back to full keyboard, the floating_Keyboard = false part of the code does not fire. This means the textView remains in the home position even though the full keyboard opens. Is anybody else experiencing this? private var floating_Keyboard: Bool = false NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardFrameWillChange), name: NSNotification.Name(rawValue: UIResponder.keyboardWillChangeFrameNotification.rawValue), object: nil) @objc func keyboardFrameWillChange(notification: NSNotification) { let userInfo = notification.userInfo! let keyBoardBeginRect = userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as! CGRect let screenBounds = UIScreen.main.bounds if (keyBoardBeginRect.equalTo(CGRect.zero)) { print("\(#function) Floating keyboard") floating_Keyboard = true if trickPatterFld.isFirstResponder { UIView.animate(withDuration: 0.3) { [weak self] in self?.bottom_Constraint.constant = self!.patter_Bottom_Constraint self?.view.layoutIfNeeded() } } } else if keyBoardBeginRect.width == screenBounds.width { print("\(#function) Full keyboard") floating_Keyboard = false if trickPatterFld.isFirstResponder { UIView.animate(withDuration: 0.3) { [weak self] in self?.bottom_Constraint.constant = self!.keyboardHeight self?.view.layoutIfNeeded() } } } } func textViewDidBeginEditing(_ textView: UITextView) { if textView.tag == 2 { set_The_Keyboard_Hgt() if textView.textColor == Theme.current.placeHolderTextColor { textView.text = "" textView.textColor = Theme.current.textColor } if floating_Keyboard == false { UIView.animate(withDuration: 0.3) { [weak self] in self?.bottom_Constraint.constant = self!.keyboardHeight self?.view.layoutIfNeeded() } } } else { if textView.textColor == Theme.current.placeHolderTextColor { textView.text = "" textView.textColor = Theme.current.textColor } } }
0
0
656
Dec ’22
How to set up an auto layout constraint to be a % value
I'm setting up auto layout constraints and I want the leading constraint of one of the controls on the view to be a fixed value on iPhone (CR) and equal to a % of the screen width for iPad. Can this be done in IB using the size inspector or does it need to be done programmatically? I've searched for documentation and looked at lots of videos but I was unable locate the information. If someone could provide a link to the documentation or share some sample code, I would be very grateful.
1
0
1.1k
Dec ’22
.main is going to be deprecated
I have this code in the sceneDelegate of my app. I understand that .main is going to be deprecated. The warning says to use view?.window?.windowScene?.screen but there is no view in sceneDelegate. How can I change let screenSize = UIScreen.main.fixedCoordinateSpace.bounds to not use .main? Thanks in advance.
8
0
3.8k
Dec ’22
Setting up keyboard avoidance to a textview using keyboardLayoutGuide
I'm setting up keyboard avoidance to a textview. Objectives: Use keyboardLayoutGuide.followsUndockedKeyboard Allow for floating keyboard on iPad Move the textView up to clear the keyboard when it's tapped Move the textView back when the keyboard is hidden or when the textView is not firstResponder View layout for testing: Three controls. A textField A TextView A UIView The constraint on the bottom of the textView is 15 pts from the top of the UIView. This constraint is set to a Priority of 750 The code I have works fine except when the iPad is rotated. keyboardWillHideNotification fires when the rotation occurs even though the keyboard stays undocked. This causes the textView to drop to its home position and then pop back up again. It's very goofy looking. The textView should hug the top of the keyboard. I tried using textViewDidEndEditing instead of keyboardWillHide but that isn't much better. Anybody have any ideas on making the textView hug the top of the keyboard when the iPad is rotated? class ViewController: UIViewController, UITextViewDelegate { @IBOutlet weak var myTextView: UITextView! private var buttomConstraint: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() myTextView.translatesAutoresizingMaskIntoConstraints = false buttomConstraint = myTextView.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor) view.keyboardLayoutGuide.followsUndockedKeyboard = true NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) hideKeyboard() } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { } @objc func keyboardWillHide(notification: NSNotification) { print("Keyboard will hide") if myTextView.isFirstResponder { UIView.animate(withDuration: 0.3) { [weak self] in self?.buttomConstraint.isActive = false self?.view.layoutIfNeeded() } } else { print("Somethibg") } } @objc func keyboardWillShow(notification: NSNotification) { if myTextView.isFirstResponder { UIView.animate(withDuration: 0.3) { [weak self] in self?.buttomConstraint.isActive = true self?.view.layoutIfNeeded() } } else { buttomConstraint.isActive = false } } func textViewDidBeginEditing(_ textView: UITextView) { // UIView.animate(withDuration: 0.3) { [weak self] in // self?.buttomConstraint.isActive = true // self?.view.layoutIfNeeded() // } } func textViewDidEndEditing(_ textView: UITextView) { // UIView.animate(withDuration: 0.3) { [weak self] in // self?.buttomConstraint.isActive = false // self?.view.layoutIfNeeded() // } } } extension ViewController { // MARK: This dismisses the keyBoard when the view it tapped func hideKeyboard() { let tap: UITapGestureRecognizer = UITapGestureRecognizer( target: self, action: #selector(ViewController.dismissKeyboard)) tap.cancelsTouchesInView = false view.addGestureRecognizer(tap) } @objc func dismissKeyboard() { view.endEditing(true) } }
2
0
1.9k
Oct ’22