Related
**Aim: ** To show latest apple calendar type of date picker(inline) in app when user wants to select the date.How it should look
Scenario:**
The user can input multiple entries (maximum 3) the exercise(suryanamaskar). These multiple entries has two functions
1.date-picker and
2.number entry(number of 'suryanamaskar')
When user clicks on the date-picker button. the date picker shows up (.inline). Each entry fetches the post API call that saves the 'suryanamaskar' count entry on server.
What is the issue: I tried to implement the date-picker using and few UI frames : .inline
I replaced the date-picker completely and implemented ".wheels" that works fine.
The datepicker is show up correctly first time. But when the user tried to add other entry or press the date entry buttton . The datepicker gets cut and is not properly visible. This is how it looks when user clicks on datepicker button second time.
What my code looks like:
import UIKit
import SwiftyJSON
import Alamofire
struct surynamaskarStruct {
var date: String
var count: String
}
class AddSuryaNamskarCountVC: UIViewController, UITextFieldDelegate {
var surynamaskarData: [surynamaskarStruct] = [
surynamaskarStruct(date: "Date", count: "0"),
surynamaskarStruct(date: "Date", count: "0"),
surynamaskarStruct(date: "Date", count: "0")
]
#IBOutlet var tableView: UITableView!
#IBOutlet weak var lblMember: UILabel!
#IBOutlet weak var btnMember: UIButton!
#IBOutlet weak var familyMemberHeightConstraint: NSLayoutConstraint!
var viewPicker : UIView!
let datePicker = UIDatePicker()
var btnIndex : Int!
var strMemberId : String!
var dicMember = [[String:Any]]()
lazy var loader : UIActivityIndicatorView = {
let indicator = UIActivityIndicatorView(style: .large)
indicator.hidesWhenStopped = true
return indicator
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if self.dicMember.count > 0 {
self.strMemberId = self.dicMember[0]["id"] as? String
self.lblMember.text = self.dicMember[0]["name"] as? String
self.familyMemberHeightConstraint.constant = 90
} else {
self.familyMemberHeightConstraint.constant = 0
}
view.addSubview(loader)
loader.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
loader.centerXAnchor.constraint(equalTo: view.centerXAnchor),
loader.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
override func viewWillAppear(_ animated: Bool) {
navigationBarDesign(txt_title: "Record Suryanamskar", showbtn: "back")
}
#IBAction func onMemberClick(_ sender: UIButton) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "PickerTableViewWithSearchViewController") as! PickerTableViewWithSearchViewController
vc.selectedItemCompletion = {dict in
self.lblMember.text = dict["name"] as? String
self.strMemberId = dict["id"] as? String
}
vc.dataSource = dicMember
vc.strNavigationTitle = "Family Member"
vc.modalPresentationStyle = UIModalPresentationStyle.fullScreen
self.present(vc, animated: true, completion: nil)
}
#IBAction func onCancelClick(_ sender: UIButton) {
self.dismiss(animated: true)
}
#IBAction func onSaveClick(_ sender: UIButton) {
var arrData = [[String:Any]]()
for arr in surynamaskarData {
if arr.date != "Date" && arr.count != "0" {
var dict = [String : Any]()
dict["date"] = arr.date
dict["count"] = arr.count
arrData.append(dict)
}
}
if arrData.count > 0 {
self.saveSuryaNamskarCountDataAPI(arrData)
////static controller to directly update the suryanamaskar chart instead of going back and then getting updated suryanamaskar
let alertController = UIAlertController(title:APP.title, message: "Suryanamaskar has been saved successfully!", preferredStyle:.alert)
let Action = UIAlertAction.init(title: "Ok", style: .default) { (UIAlertAction) in
// Write Your code Here
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SuryaNamskarVC") as! SuryaNamskarVC
vc.modalPresentationStyle = UIModalPresentationStyle.fullScreen
// vc.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(vc, animated: true, completion: nil)
}
alertController.addAction(Action)
self.present(alertController, animated: true, completion: nil)
//// Till here for alert controller. if not implemented, updated suryanamaskar will happen only once user goes back and comes back to suryanamaskarVC
}
// else {
// showAlert(title: APP.title, message: "Please select date and count before Save")
// }
}
// MARK: - DatePicker functions
func showDatePicker(){
viewPicker = UIView(frame: CGRect(x: 0.0, y: self.view.frame.height - 380, width: self.view.frame.width, height: 380))
viewPicker.backgroundColor = UIColor.white
viewPicker.clipsToBounds = true
// Posiiton date picket within a view
datePicker.frame = CGRect(x: 10, y: 50, width: self.view.frame.width, height: 200)
datePicker.datePickerMode = .date
datePicker.minimumDate = Calendar.current.date(byAdding: .month, value: -2, to: Date())
datePicker.maximumDate = Calendar.current.date(byAdding: .year, value: 0, to: Date())
datePicker.backgroundColor = UIColor.white
if #available(iOS 14.0, *) {
datePicker.preferredDatePickerStyle = .inline
} else {
if #available(iOS 13.4, *) {
datePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions
}
// Fallback on earlier versions
}
// Add an event to call onDidChangeDate function when value is changed.
datePicker.addTarget(self, action: #selector(AddMemberStep1VC.datePickerValueChanged(_:)), for: .valueChanged)
datePicker.center.x = self.view.center.x
//ToolBar
var toolbar = UIToolbar();
toolbar.sizeToFit()
toolbar = UIToolbar(frame: CGRect(x: 0.0, y: 0.0, width: self.view.frame.width, height: 50))
let doneButton = UIBarButtonItem(title: "done".localized, style: .plain, target: self, action: #selector(donedatePicker));
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "cancel".localized, style: .plain, target: self, action: #selector(cancelDatePicker));
toolbar.setItems([doneButton,spaceButton,cancelButton], animated: false)
// txtDate.inputAccessoryView = toolbar
// txtDate.inputView = datePicker
self.viewPicker.addSubview(toolbar)
self.viewPicker.addSubview(datePicker)
self.viewPicker.clipsToBounds = true
self.view.addSubview(self.viewPicker)
}
#objc func datePickerValueChanged(_ sender: UIDatePicker){
// Create date formatter
let dateFormatter: DateFormatter = DateFormatter()
// Set date format
dateFormatter.dateFormat = "dd/MM/yyyy"
// Apply date format
let _: String = dateFormatter.string(from: sender.date)
// print("Selected value \(selectedDate)")
}
#objc func donedatePicker(){
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
let strDate = formatter.string(from: datePicker.date)
surynamaskarData[btnIndex].date = strDate
DispatchQueue.main.async {
self.tableView.reloadData()
}
self.viewPicker.isHidden = true
}
#objc func cancelDatePicker(){
self.viewPicker.isHidden = true
}
#objc func onAddMoreClicked() {
print("AddMore Button Pressed")
for i in surynamaskarData {
if i.date == "Date" || i.count == "0" || i.count == "" {
showAlert(title: APP.title, message: "Please select date and count before AddMore")
return
}
}
surynamaskarData.append(surynamaskarStruct(date: "Date", count: "0"))
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
#objc func onDateClick(_ sender: UIButton) {
btnIndex = sender.tag
view.endEditing(true)
if self.viewPicker == nil {
self.showDatePicker()
} else {
if self.viewPicker.isHidden == true {
self.showDatePicker()
} else {
self.viewPicker.isHidden = true
}
}
}
#objc func onDeleteClick(_ sender: UIButton) {
surynamaskarData.remove(at: sender.tag)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if self.viewPicker != nil {
if self.viewPicker.isHidden == false {
self.viewPicker.isHidden = false
}
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
if textField.text == "" {
textField.text = "0"
}
surynamaskarData[textField.tag].count = textField.text ?? "0"
}
func json(from object:Any) -> String? {
guard let data = try? JSONSerialization.data(withJSONObject: object, options: []) else {
return nil
}
return String(data: data, encoding: String.Encoding.utf8)
}
func saveSuryaNamskarCountDataAPI(_ data : [[String:Any]]) {
var parameters: [String: Any] = [:]
parameters["surynamaskar"] = self.json(from: data)
parameters["member_id"] = self.strMemberId // _appDelegator.dicDataProfile![0]["member_id"] as? String
print(parameters)
// APIUrl.save_suryanamaskar
//live API only
//"https://myhss.org.uk/api/v1/suryanamaskar/save_suryanamaskar_count"
loader.startAnimating()
let url = URL(string: APIUrl.save_suryanamaskar)!
AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default)
.validate()
.responseJSON { response in
self.loader.stopAnimating()
switch response.result {
case .success(let response):
print(response)
let jsonData = JSON(response)
if let status = jsonData["status"].int
{
if status == 1
{
let strMessage : String = jsonData["message"].rawValue as! String
print(strMessage)
// create the alert
let alert = UIAlertController(title: APP.title, message: strMessage, preferredStyle: UIAlertController.Style.alert)
// add an action (button)
let ok = UIAlertAction(title: "Ok".localized, style: .default, handler: { action in
DispatchQueue.main.async {
self.dismiss(animated: true)
}
})
alert.addAction(ok)
// show the alert
self.present(alert, animated: true, completion: nil)
} else {
if let strError = jsonData["message"].string {
showAlert(title: APP.title, message: strError)
}
}
}
case .failure(let error):
print(error.localizedDescription)
showAlert(title: APP.title, message: error.localizedDescription)
}
}
}
}
extension AddSuryaNamskarCountVC : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return surynamaskarData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: AddSuryaNamskarCountTVCell.cellIdentifier) as! AddSuryaNamskarCountTVCell
cell.btnDate.tag = indexPath.row
cell.btnDate.addTarget(self, action: #selector(self.onDateClick(_:)), for: .touchUpInside)
cell.btnCancel.tag = indexPath.row
cell.btnCancel.addTarget(self, action: #selector(self.onDeleteClick(_:)), for: .touchUpInside)
cell.lblDate.text = surynamaskarData[indexPath.row].date
cell.txtCount.text = surynamaskarData[indexPath.row].count
cell.txtCount.tag = indexPath.row
cell.txtCount.delegate = self
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60.0
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let viewFooter = UIView()
viewFooter.backgroundColor = UIColor.systemGray5
let size = tableView.frame.size
let addMoreButton = UIButton()
addMoreButton.setTitle("+ Add More", for: .normal)
addMoreButton.setTitleColor(Colors.txtAppDarkColor, for: .normal)
addMoreButton.frame = CGRect(x: 0, y: 0, width: size.width, height: 50)
addMoreButton.addTarget(self, action: #selector(onAddMoreClicked), for: .touchUpInside)
viewFooter.addSubview(addMoreButton)
return viewFooter
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 50
}
}
Changing the Co-ordinates works:
Following co-orinates fixes the calender view for this issue.
func showDatePicker(){
viewPicker = UIView(frame: CGRect(x: 0.0, y: self.view.frame.height - 500, width: self.view.frame.width, height: 500))
viewPicker.backgroundColor = UIColor.white
viewPicker.clipsToBounds = true
// Posiiton date picket within a view
datePicker.frame = CGRect(x: 10, y: 50, width: self.view.frame.width, height: 500)
datePicker.datePickerMode = .date
datePicker.minimumDate = Calendar.current.date(byAdding: .month, value: -2, to: Date())
datePicker.maximumDate = Calendar.current.date(byAdding: .year, value: 0, to: Date())
datePicker.backgroundColor = UIColor.white
if #available(iOS 14.0, *) {
datePicker.preferredDatePickerStyle = .inline
} else {
if #available(iOS 13.4, *) {
datePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions
}
// Fallback on earlier versions
}
// Add an event to call onDidChangeDate function when value is changed.
datePicker.addTarget(self, action: #selector(AddMemberStep1VC.datePickerValueChanged(_:)), for: .valueChanged)
datePicker.center.x = self.view.center.x
//ToolBar
var toolbar = UIToolbar();
toolbar.sizeToFit()
toolbar = UIToolbar(frame: CGRect(x: 0.0, y: 0.0, width: self.view.frame.width, height: 50))
let doneButton = UIBarButtonItem(title: "done".localized, style: .plain, target: self, action: #selector(donedatePicker));
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "cancel".localized, style: .plain, target: self, action: #selector(cancelDatePicker));
toolbar.setItems([doneButton,spaceButton,cancelButton], animated: false)
self.viewPicker.addSubview(toolbar)
self.viewPicker.addSubview(datePicker)
self.viewPicker.clipsToBounds = true
self.view.addSubview(self.viewPicker)
}
I am trying to get all the elements (UItextfields) that I have in defined in myScrollView in class AddViewController to another FormViewController where I have just an empty getFormView scrollview where I want to get all the elements of myScrollView to be appear, whether in a form of copy or getting that same.
I am adding subview of myScrollView to getFormView but this gives me error
unexpectedly found nil while unwrapping an optional
I am creating textfields by getting an input, like if set input to 7 the seven textfields will be generated in form and by clicking on creating I want these testfields should be in formViewController's uiscrollview that is getformview
FormViewController
import UIKit
class FormViewController: UIViewController {
#IBOutlet weak var menu: UIBarButtonItem!
#IBOutlet weak var getFormView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
menu.target = revealViewController()
menu.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
getFormView.alwaysBounceVertical = true
getFormView.scrollsToTop = true
getFormView.isScrollEnabled = true
getFormView.contentSize = CGSize(width: 343, height: 1500)
print("formViewController")
let mainStoryBoard: UIStoryboard = UIStoryboard(name: "Main", bundle : nil)
let desController = mainStoryBoard.instantiateViewController(withIdentifier: "AddViewController") as! AddViewController
self.view.addSubview(self.getFormView)
self.getFormView.addSubview(desController.myScrollView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
AddViewController Image of my myScrollView
enter image description here
FormViewController image of getFormView
enter image description here
AddViewController
import UIKit
class AddViewController: UIViewController {
var templateName : String?
var templateDesc : String?
var noButtons : Int?
var noTextFields : Int?
var noLabels : Int?
var xValue = 20, yValue = 100
var tagNo = 0
var textObjects : Array<Any>?
var incrementerText : Int?
var xButton = 15 , yButton = 90
var tagButton = 10
var buttonObject : Array<Any>?
var buttonIncreament : Int?
var xLabel = 10 , yLabel = 80
var tagLabel = 15
var labelObject : Array<Any>?
var labelIncreament : Int?
#IBOutlet weak var menu: UIBarButtonItem!
#IBOutlet weak var myScrollView: UIScrollView!
#IBOutlet weak var reset: UIButton!
#IBAction func reset(_ sender: Any) {
let mainStoryBoard: UIStoryboard = UIStoryboard(name: "Main", bundle : nil)
let desController = mainStoryBoard.instantiateViewController(withIdentifier: "AddViewController") as! AddViewController
let newFrontViewController = UINavigationController.init(rootViewController:desController)
revealViewController().pushFrontViewController(newFrontViewController, animated: true)
}
#IBOutlet weak var createForms: UIButton!
#IBAction func createForms(_ sender: Any) {
let mainStoryBoard: UIStoryboard = UIStoryboard(name: "Main", bundle : nil)
let desController = mainStoryBoard.instantiateViewController(withIdentifier: "FormViewController") as! FormViewController
// desController.getFormView.addSubview(myScrollView)
let newFrontViewController = UINavigationController.init(rootViewController:desController)
revealViewController().pushFrontViewController(newFrontViewController, animated: true)
}
#IBAction func addForm(_ sender: Any) {
let alertController = UIAlertController(title: "Create Template", message: "", preferredStyle: .alert)
alertController.extendedLayoutIncludesOpaqueBars = true
alertController.addTextField { (textField: UITextField) in
// textField.keyboardAppearance = .dark
textField.keyboardType = .default
textField.autocorrectionType = .default
textField.placeholder = "Title"
textField.clearButtonMode = .whileEditing
}
alertController.addTextField { (textField: UITextField) in
//textField.keyboardAppearance = .dark
textField.keyboardType = .default
textField.autocorrectionType = .default
textField.placeholder = "Description"
textField.clearButtonMode = .whileEditing
}
let okAction = UIAlertAction(title: "Continue", style: UIAlertActionStyle.default) {
UIAlertAction in
print("Ok action")
let templateText = alertController.textFields![0]
let descriptionText = alertController.textFields![1]
self.templateName = templateText.text!
self.templateDesc = descriptionText.text!
if self.templateName?.isEmpty == false && self.templateDesc?.isEmpty == false {
print("Template: \(templateText.text!)\nDescription: \(descriptionText.text!)")
print("\(String(describing: self.templateName!)), \(String(describing: self.templateDesc!))")
self.dismiss(animated: true, completion: nil)
self.drawPop()
}
else {
self.okAlert()
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive) {
UIAlertAction in
self.dismiss(animated: true, completion: nil)
NSLog("Cancel Pressed")
}
//alertController.addAction(alertActionOkay)
// Add the actions
alertController.addAction(cancelAction)
alertController.addAction(okAction)
// alertController.willChangeValue(forKey: "Continue")
// Present the controller
self.present(alertController, animated: true, completion: nil)
}
func drawPop() {
let alertController = UIAlertController(title: "\(self.templateName!)", message: "\(self.templateDesc!)", preferredStyle: .alert)
//attributing textfields labels
alertController.addTextField { (textField: UITextField) in
//textField.keyboardAppearance = .dark
textField.keyboardType = UIKeyboardType.numberPad
// textField.keyboardType = .default
textField.placeholder = "TextFileds"
textField.clearButtonMode = .whileEditing
}
alertController.addTextField { (textField: UITextField) in
// textField.keyboardAppearance = .dark
textField.keyboardType = UIKeyboardType.numberPad
textField.autocorrectionType = .default
textField.placeholder = "Buttons"
textField.clearButtonMode = .whileEditing
}
alertController.addTextField { (textField: UITextField) in
// textField.keyboardAppearance = .dark
textField.keyboardType = UIKeyboardType.numberPad
textField.autocorrectionType = .default
textField.placeholder = "Labels"
textField.clearButtonMode = .whileEditing
}
// Create the actions
let okAction = UIAlertAction(title: "Done", style: UIAlertActionStyle.default) {
UIAlertAction in
NSLog("OK Pressed")
let notextFieldText = alertController.textFields![0]
let noButtonText = alertController.textFields![1]
let noLabelText = alertController.textFields![2]
self.noTextFields = Int(notextFieldText.text!)
self.noButtons = Int(noButtonText.text!)
self.noLabels = Int(noButtonText.text!)
print("Template: \(notextFieldText.text!)\nDescription: \(noButtonText.text!)")
print("\(noLabelText.text!)")
print("\(String(describing: self.noTextFields!)), \(String(describing: self.noButtons!)) , \(String(describing: self.noLabels!))")
self.createForms.isHidden = false
self.myScrollView.isHidden = false
self.reset.isHidden = false
self.incrementerText = 20
if self.noTextFields! > 0 {
for _ in 0..<self.noTextFields! {
print ("hello")
let sampleTextField = UITextField(frame: CGRect(x: self.xValue, y: self.yValue, width: 300, height: 40))
sampleTextField.placeholder = "Enter text here"
sampleTextField.font = UIFont.systemFont(ofSize: 15)
sampleTextField.borderStyle = UITextBorderStyle.roundedRect
sampleTextField.autocorrectionType = UITextAutocorrectionType.no
sampleTextField.keyboardType = UIKeyboardType.default
sampleTextField.returnKeyType = UIReturnKeyType.done
sampleTextField.clearButtonMode = UITextFieldViewMode.whileEditing;
sampleTextField.contentVerticalAlignment = UIControlContentVerticalAlignment.center
sampleTextField.delegate = self as? UITextFieldDelegate
sampleTextField.tag = self.tagNo
// self.view.addSubview(sampleTextField)
//trying to print at container view
self.view.addSubview(self.myScrollView)
self.myScrollView.addSubview(sampleTextField)
let frametext = sampleTextField.frame.size.height
self.textObjects?.append(sampleTextField)
self.yValue = self.yValue + Int(frametext) + 20
self.xValue = 20
}
}
else {
print("no text field found")
}
self.buttonIncreament = 20
if self.noButtons! > 0 {
for _ in 0..<self.noButtons! {
print ("Buttons")
let sampleButton = UIButton(frame: CGRect(x: self.xButton, y: self.yButton, width: 150, height: 25))
sampleButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center
sampleButton.tag = self.tagNo
// self.view.addSubview(sampleButton)
let frametext = sampleButton.frame.size.height
self.view.addSubview(self.myScrollView)
self.myScrollView.addSubview(sampleButton)
self.buttonObject?.append(sampleButton)
self.yButton = self.yButton + Int(frametext) + 20
self.xButton = 20
}
}
else {
print("no button found")
}
self.labelIncreament = 20
if self.noLabels! > 0 {
for _ in 0..<self.noLabels! {
print ("Labels")
let sampleLabel = UILabel(frame: CGRect(x: self.xLabel, y: self.yLabel, width: 150, height: 25))
// sampleLabel.contentVerticalAlignment = UIControlContentVerticalAlignment.center
sampleLabel.tag = self.tagNo
// self.view.addSubview(sampleButton)
let frameLabel = sampleLabel.frame.size.height
self.view.addSubview(self.myScrollView)
self.myScrollView.addSubview(sampleLabel)
self.labelObject?.append(sampleLabel)
self.yLabel = self.yLabel + Int(frameLabel) + 20
self.xLabel = 20
}
}
else {
print("no button found")
}
self.dismiss(animated: true, completion: nil)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive) {
UIAlertAction in
self.dismiss(animated: true, completion: nil)
NSLog("Cancel Pressed")
}
//alertController.addAction(alertActionOkay)
// Add the actions
alertController.addAction(cancelAction)
alertController.addAction(okAction)
// Present the controller
self.present(alertController, animated: true, completion: nil)
}
func createForm() {
let sampleTextField = UITextField(frame: CGRect(x: 20, y: 100, width: 300, height: 40))
sampleTextField.placeholder = "Enter text here"
sampleTextField.font = UIFont.systemFont(ofSize: 15)
sampleTextField.borderStyle = UITextBorderStyle.roundedRect
sampleTextField.autocorrectionType = UITextAutocorrectionType.no
sampleTextField.keyboardType = UIKeyboardType.default
sampleTextField.returnKeyType = UIReturnKeyType.done
sampleTextField.clearButtonMode = UITextFieldViewMode.whileEditing;
sampleTextField.contentVerticalAlignment = UIControlContentVerticalAlignment.center
sampleTextField.delegate = self as? UITextFieldDelegate
self.view.addSubview(sampleTextField)
}
func okAlert() {
let alertController = UIAlertController(title: "Oops!", message: "Enter required data", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
/*
let scrollmyView : UIScrollView = {
let scrollView = UIScrollView()
scrollView.alwaysBounceVertical = true
scrollView.scrollsToTop = true
// myScrollView.alwaysBounceHorizontal = true
scrollView.isScrollEnabled = true
scrollView.contentSize = CGSize(width: 200, height: 1500)
return scrollView
}()
*/
override func viewDidLoad() {
super.viewDidLoad()
menu.target = revealViewController()
menu.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
myScrollView.alwaysBounceVertical = true
myScrollView.scrollsToTop = true
// myScrollView.alwaysBounceHorizontal = true
myScrollView.isScrollEnabled = true
myScrollView.contentSize = CGSize(width: 343, height: 1500)
// scroller.contentSize = CGSize(width: yourWidth, height: yourHeight)
createForms.isHidden = true
myScrollView.isHidden = true
reset.isHidden = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Error
Full screen error
Why you are using scrollview if you have same type of elements. Best way is to use table view. We use scrollview if the elements in most of the rows are different. Once you use table view you don't have to copy anything.
Best approach for your problem:
If you have same type of view controller then you can use one view controller as AddViewController and FormViewController.
Create the same UITextFields in your FormViewController.
and when a user fills the form in AddViewController , update the textfields of your FormViewController with the text of AddViewController's text field
content.view.frame = CGRect(x: -UIScreen.main.bounds.size.width, y: 0, width: UIScreen.main.bounds.size.width, height: view.frame.size.height)
getFormView = content.scrollView
view.addSubview(content.scollView)
content.didMove(toParentViewController: self)
Here content is the view controller that you want to add in you case it is instance of AddViewController
This Code Seems to be crashing my code.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'attempt to scroll to invalid
index path: {length = 2, path = 0 - 3}'
func handleKeyboardNotification(notification: NSNotification) {
if let userinfo = notification.userInfo {
let keyboardFrame = (userinfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
self.bottomConstraint?.constant = -(keyboardFrame.height)
let isKeyboardShowing = notification.name == NSNotification.Name.UIKeyboardWillShow
self.bottomConstraint?.constant = isKeyboardShowing ? -keyboardFrame.height : 0
UIView.animate(withDuration: 0, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: { (completion) in
if self.comments.count > 0 && isKeyboardShowing {
let indexPath = NSIndexPath(item: self.comments.count - 1, section: 0)
self.collectionView.scrollToItem(at: indexPath as IndexPath, at: .top, animated: true)
}
})
}
}
I am also using IGListKit to populate the collection view that this is contained in. Below is my comments controller.
import UIKit
import IGListKit
import Firebase
class NewCommentsViewController: UIViewController, UITextFieldDelegate {
//array of comments which will be loaded by a service function
var comments = [CommentGrabbed]()
var messagesRef: DatabaseReference?
var bottomConstraint: NSLayoutConstraint?
public var eventKey = ""
//This creates a lazily-initialized variable for the IGListAdapter. The initializer requires three parameters:
//1 updater is an object conforming to IGListUpdatingDelegate, which handles row and section updates. IGListAdapterUpdater is a default implementation that is suitable for your usage.
//2 viewController is a UIViewController that houses the adapter. This view controller is later used for navigating to other view controllers.
//3 workingRangeSize is the size of the working range, which allows you to prepare content for sections just outside of the visible frame.
lazy var adapter: ListAdapter = {
return ListAdapter(updater: ListAdapterUpdater(), viewController: self, workingRangeSize: 0)
}()
// 1 IGListKit uses IGListCollectionView, which is a subclass of UICollectionView, which patches some functionality and prevents others.
let collectionView: UICollectionView = {
// 2 This starts with a zero-sized rect since the view isn’t created yet. It uses the UICollectionViewFlowLayout just as the ClassicFeedViewController did.
let view = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout())
// 3 The background color is set to white
view.backgroundColor = UIColor.white
return view
}()
//will fetch the comments from the database and append them to an array
fileprivate func fetchComments() {
messagesRef = Database.database().reference().child("Comments").child(eventKey)
print(eventKey)
print(comments.count)
messagesRef?.observe(.childAdded, with: { (snapshot) in
print(snapshot)
guard let commentDictionary = snapshot.value as? [String: Any] else {
return
}
print(commentDictionary)
guard let uid = commentDictionary["uid"] as? String else {
return
}
UserService.show(forUID: uid, completion: { (user) in
if let user = user {
var commentFetched = CommentGrabbed(user: user, dictionary: commentDictionary)
commentFetched.commentID = snapshot.key
let filteredArr = self.comments.filter { (comment) -> Bool in
return comment.commentID == commentFetched.commentID
}
if filteredArr.count == 0 {
self.comments.append(commentFetched)
}
print(self.comments)
self.adapter.performUpdates(animated: true)
}
self.comments.sort(by: { (comment1, comment2) -> Bool in
return comment1.creationDate.compare(comment2.creationDate) == .orderedAscending
})
})
}, withCancel: { (error) in
print("Failed to observe comments")
})
//first lets fetch comments for current event
}
lazy var submitButton: UIButton = {
let submitButton = UIButton(type: .system)
submitButton.setTitle("Submit", for: .normal)
submitButton.setTitleColor(.black, for: .normal)
submitButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
submitButton.addTarget(self, action: #selector(handleSubmit), for: .touchUpInside)
submitButton.isEnabled = false
return submitButton
}()
//allows you to gain access to the input accessory view that each view controller has for inputting text
lazy var containerView: UIView = {
let containerView = UIView()
containerView.backgroundColor = .white
containerView.addSubview(self.submitButton)
self.submitButton.anchor(top: containerView.topAnchor, left: nil, bottom: containerView.bottomAnchor, right: containerView.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 12, width: 50, height: 0)
containerView.addSubview(self.commentTextField)
self.commentTextField.anchor(top: containerView.topAnchor, left: containerView.leftAnchor, bottom: containerView.bottomAnchor, right: self.submitButton.leftAnchor, paddingTop: 0, paddingLeft: 12, paddingBottom: 0, paddingRight: 180, width: 0, height: 0)
self.commentTextField.delegate = self
let lineSeparatorView = UIView()
lineSeparatorView.backgroundColor = UIColor.rgb(red: 230, green: 230, blue: 230)
containerView.addSubview(lineSeparatorView)
lineSeparatorView.anchor(top: containerView.topAnchor, left: containerView.leftAnchor, bottom: nil, right: containerView.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0.5)
return containerView
}()
lazy var commentTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "Add a comment"
textField.delegate = self
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
return textField
}()
func textFieldDidChange(_ textField: UITextField) {
let isCommentValid = commentTextField.text?.characters.count ?? 0 > 0
if isCommentValid {
submitButton.isEnabled = true
} else {
submitButton.isEnabled = false
}
}
func handleSubmit() {
guard let comment = commentTextField.text, comment.characters.count > 0 else {
return
}
let userText = Comments(content: comment, uid: User.current.uid, profilePic: User.current.profilePic!)
sendMessage(userText)
// will remove text after entered
self.commentTextField.text = nil
}
func flagButtonTapped (from cell: CommentCell) {
guard let indexPath = collectionView.indexPath(for: cell) else { return }
// 2
let comment = comments[indexPath.item]
// 3
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
// 4
if comment.uid != User.current.uid {
let flagAction = UIAlertAction(title: "Report as Inappropriate", style: .default) { _ in
ChatService.flag(comment)
let okAlert = UIAlertController(title: nil, message: "The post has been flagged.", preferredStyle: .alert)
okAlert.addAction(UIAlertAction(title: "Ok", style: .default))
self.present(okAlert, animated: true)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
alertController.addAction(flagAction)
} else {
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let deleteAction = UIAlertAction(title: "Delete Comment", style: .default, handler: { _ in
ChatService.deleteComment(comment, self.eventKey)
let okAlert = UIAlertController(title: nil, message: "Comment Has Been Deleted", preferredStyle: .alert)
okAlert.addAction(UIAlertAction(title: "Ok", style: .default))
self.present(okAlert, animated: true)
})
alertController.addAction(cancelAction)
alertController.addAction(deleteAction)
}
present(alertController, animated: true, completion: nil)
}
func handleKeyboardNotification(notification: NSNotification) {
if let userinfo = notification.userInfo {
let keyboardFrame = (userinfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
self.bottomConstraint?.constant = -keyboardFrame.height
let isKeyboardShowing = notification.name == NSNotification.Name.UIKeyboardWillShow
self.bottomConstraint?.constant = isKeyboardShowing ? -keyboardFrame.height : 0
UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: { (completion) in
if self.comments.count > 0 && isKeyboardShowing {
let indexPath = NSIndexPath(item: self.comments.count - 1, section: 0)
self.collectionView.scrollToItem(at: indexPath as IndexPath, at: .top, animated: true)
}
})
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
collectionView.addSubview(containerView)
collectionView.alwaysBounceVertical = true
view.addConstraintsWithFormatt("H:|[v0]|", views: containerView)
view.addConstraintsWithFormatt("V:[v0(48)]", views: containerView)
bottomConstraint = NSLayoutConstraint(item: containerView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
view.addConstraint(bottomConstraint!)
adapter.collectionView = collectionView
adapter.dataSource = self
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
collectionView.register(CommentCell.self, forCellWithReuseIdentifier: "CommentCell")
fetchComments()
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tabBarController?.tabBar.isHidden = true
submitButton.isUserInteractionEnabled = true
}
//viewDidLayoutSubviews() is overridden, setting the collectionView frame to match the view bounds.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.frame = view.bounds
}
}
extension NewCommentsViewController: ListAdapterDataSource {
// 1 objects(for:) returns an array of data objects that should show up in the collection view. loader.entries is provided here as it contains the journal entries.
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
print("comments = \(comments)")
return comments
}
// 2 For each data object, listAdapter(_:sectionControllerFor:) must return a new instance of a section controller. For now you’re returning a plain IGListSectionController to appease the compiler — in a moment, you’ll modify this to return a custom journal section controller.
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
//the comment section controller will be placed here but we don't have it yet so this will be a placeholder
return CommentsSectionController()
}
// 3 emptyView(for:) returns a view that should be displayed when the list is empty. NASA is in a bit of a time crunch, so they didn’t budget for this feature.
func emptyView(for listAdapter: ListAdapter) -> UIView? {
let view = UIView()
view.backgroundColor = UIColor.white
return view
}
}
extension NewCommentsViewController {
func sendMessage(_ message: Comments) {
ChatService.sendMessage(message, eventKey: eventKey)
}
}
Also this is my section controller. Now it is loading the data but as soon as I try to add someething to test if it is working properly using the keyboard it crashes.
import UIKit
import IGListKit
import Foundation
class CommentsSectionController: ListSectionController {
var comment: CommentGrabbed?
override init() {
super.init()
inset = UIEdgeInsets(top: 0, left: 0, bottom: 15, right: 0)
}
// MARK: IGListSectionController Overrides
override func numberOfItems() -> Int {
print(numberOfItems)
return 1
}
override func sizeForItem(at index: Int) -> CGSize {
let frame = CGRect(x: 0, y: 0, width: collectionContext!.containerSize.width, height: 50)
let dummyCell = CommentCell(frame: frame)
dummyCell.comment = comment
dummyCell.layoutIfNeeded()
let targetSize = CGSize(width: collectionContext!.containerSize.width, height: 55)
let estimatedSize = dummyCell.systemLayoutSizeFitting(targetSize)
let height = max(40 + 8 + 8, estimatedSize.height)
return CGSize(width: collectionContext!.containerSize.width, height: height)
}
override var minimumLineSpacing: CGFloat {
get {
return 0.0
}
set {
self.minimumLineSpacing = 0.0
}
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
guard let cell = collectionContext?.dequeueReusableCell(of: CommentCell.self, for: self, at: index) as? CommentCell else {
fatalError()
}
print(comment)
cell.comment = comment
return cell
}
override func didUpdate(to object: Any) {
comment = object as! CommentGrabbed
}
override func didSelectItem(at index: Int) {
}
}
This specific method is responsbile for returning cells
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
//the comment section controller will be placed here but we don't have it yet so this will be a placeholder
return CommentsSectionController()
}
Any insight would be very helpful
This is happening because you set the number of items for your collection to be equal to 1, but you are trying to access a cell that has an index equal to IndexPath(section: 0, item: self:comments.count-1), and comments.count-1 is equal to 3 in this case as you can guess from the error log, which is why you get this error.
The solution here would be returning the correct amount of comments (comments.count-1) for your collection view data source.
UPDATE:
In that case, you should not use NSIndexPath. Instead, use IndexPath. Also, after this change you no longer need to cast your index path as IndexPath in your scrollToItem call. The updated version would look like this:
func handleKeyboardNotification(notification: NSNotification) {
// ...
UIView.animate(withDuration: 0, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: { (completion) in
if self.comments.count > 0 && isKeyboardShowing {
let indexPath = IndexPath(item: self.comments.count-1, section: 0)
self.collectionView.scrollToItem(at: indexPath, at: .top, animated: true)
}
})
}
}
I choose photos from the photo library, unable to get a photo in the table view.
I got Error:
[Generic] Creating an image format with an unknown type is an error
extension EditProfileViewController: GMPickerDelegate {
func gmPicker(_ gmPicker: GMPicker, didSelect string: String) {
self.genderStr = string
self.tableView.reloadData()
}
func gmPickerDidCancelSelection(_ gmPicker: GMPicker) {
}
fileprivate func setupPickerView() {
picker.delegate = self
picker.config.animationDuration = 0.5
picker.config.cancelButtonTitle = "Cancel"
picker.config.confirmButtonTitle = "Confirm"
picker.config.contentBackgroundColor = UIColor(red: 253/255.0, green: 253/255.0, blue: 253/255.0, alpha: 1)
picker.config.headerBackgroundColor = UIColor(red: 244/255.0, green: 244/255.0, blue: 244/255.0, alpha: 1)
picker.config.confirmButtonColor = UIColor.black
picker.config.cancelButtonColor = UIColor.black
}
}
class EditProfileViewController: UIViewController, UITableViewDelegate, UITableViewDataSource,UIPickerViewDelegate,UIImagePickerControllerDelegate, UINavigationControllerDelegate,UIActionSheetDelegate{
var picker = GMPicker()
let pickerBgView = UIView(frame: CGRect(x: 0,y: 0,width: 30,height: 250))
var pickerView = UIPickerView()
var addressRecord = [String]()
var image1 = UIImage()
let imagePicker: UIImagePickerController! = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "RoundImgCell", bundle: nil), forCellReuseIdentifier: "CellImg")
pickerView.frame = CGRect(x: 0,y: -20,width: self.view.frame.width,height: 250)//UIPickerView(frame: CGRectMake(0,20,self.view.frame.width,250))
pickerView.delegate = self
pickerBgView.backgroundColor = UIColor.yellow
let toolbar = UIToolbar(frame: CGRect(x: 0,y: 0,width: self.view.frame.width,height: 40))
toolbar.barStyle = .black
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(EditProfileViewController.doneAction))
doneButton.tintColor = UIColor.white
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: #selector(EditProfileViewController.doneAction))
let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.done, target: self, action: #selector(EditProfileViewController.cancelAction))
cancelButton.tintColor = UIColor.white
pickerBgView.addSubview(toolbar)
pickerBgView.addSubview(pickerView)
toolbar.setItems([doneButton,space,cancelButton], animated: true)
imagePicker.delegate = self
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return self.addressRecord.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return self.addressRecord[row]
}
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
uploadImageMethod()
}
}
func uploadImageMethod() {
let actionSheetController: UIAlertController = UIAlertController(title: "Action Sheet", message: "Now! Choose an option!", preferredStyle: .actionSheet)
let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in
//Just dismiss the action sheet
}
actionSheetController.addAction(cancelAction)
//Create and add first option action
let takePictureAction: UIAlertAction = UIAlertAction(title: "Take Picture", style: .default) { action -> Void in
if (UIImagePickerController.isSourceTypeAvailable(.camera)) {
if UIImagePickerController.availableCaptureModes(for: .rear) != nil {
self.imagePicker.allowsEditing = false
self.imagePicker.sourceType = .camera
self.imagePicker.delegate = self
self.imagePicker.cameraCaptureMode = .photo
self.present(self.imagePicker, animated: true, completion: {})
} else {
print("Rear camera doesn't exist.")
}
} else if (UIImagePickerController.isSourceTypeAvailable(.photoLibrary)) {
self.imagePicker.sourceType = .photoLibrary
self.imagePicker.delegate = self
self.present(self.imagePicker, animated: true, completion: {})
}
}
actionSheetController.addAction(takePictureAction)
//Create and add a second option action
let choosePictureAction: UIAlertAction = UIAlertAction(title: "Choose From Camera Roll", style: .default) { action -> Void in
self.imagePicker.sourceType = .photoLibrary
self.imagePicker.delegate = self
self.present(self.imagePicker, animated: true, completion: {})
}
actionSheetController.addAction(choosePictureAction)
//Present the AlertController
self.present(actionSheetController, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
print("select below")
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
//imagePost.image = image //updated
// image1.image = image
print("picked")
print(image)
} else{
print("Something went wrong")
}
self.dismiss(animated: true, completion: nil)
}
}
Error:
Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/AssetsLibraryServices.framework/AssetsLibraryServices (0x12140acc0) and /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/PhotoLibraryServices.framework/PhotoLibraryServices
One of the two will be used. Which one is undefined.
[Generic] Creating an image format with an unknown type is an error
i have an AlertController with UITextView.
when UITexView become first responder the alter doesn't move up with the keyboard.
this is my code:
#IBAction func showAlert(sender: AnyObject) {
let alertController = UIAlertController(title: "Hello, I'm alert! \n\n\n\n\n\n\n", message: "", preferredStyle: .alert)
let rect = CGRect(x: 15, y: 15, width: 240, height: 150)//CGRectMake(15, 50, 240, 150.0)
let textView = UITextView(frame: rect)
textView.font = UIFont(name: "Helvetica", size: 15)
textView.textColor = UIColor.lightGray
textView.backgroundColor = UIColor.white
textView.layer.borderColor = UIColor.lightGray.cgColor
textView.layer.borderWidth = 1.0
textView.text = "Enter message here"
textView.delegate = self
alertController.view.addSubview(textView)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let action = UIAlertAction(title: "Ok", style: .default, handler: { action in
let msg = (textView.textColor == UIColor.lightGray) ? "" : textView.text
print(msg!)
})
alertController.addAction(cancel)
alertController.addAction(action)
self.present(alertController, animated: true, completion: {
textView.becomeFirstResponder()
})
}
and this is my result:
there is a solution?
thanks in advance
just addTextField and then remove it
alert.addTextField { field in
field.translatesAutoresizingMaskIntoConstraints = false
field.heightAnchor.constraint(equalToConstant: 0).isActive = true
}
let inCntrlr = alert.childViewControllers[0].view!
inCntrlr.removeFromSuperview()
and then you could add your own views. here is a
result
After presenting alert controller. Open keyboard for TextView and move alert controller up.
I hope this will suite for you.
self.present(alertController, animated: true, completion: {
textView.becomeFirstResponder()
UIView.animate(withDuration: 0.5, animations: {
alertController.view.frame.origin.y = 100
})
})
UIAlertController by default will slide up when they keyboard is shown. The problem here is that you have added a subview to the alert controller. From the UIAlertController docs:
The UIAlertController class is intended to be used as-is and does not
support subclassing. The view hierarchy for this class is private and
must not be modified.
Adding your own subview to the alert goes against what the docs say and is likely what is causing your problem. If you need an alert with a text view in it, your best bet is to create your own view and manage it yourself.
I created this drop-in replacement, also customizable for any special needs of course. It's pretty simple and 'just works'!
https://gist.github.com/unixb0y/42a1ae0fb707bdb5e1e484bafd33d44a
It is a subclass of UIAlertController with a UITextView inside.
When it is initialized, it observes keyboard changes and adjusts its view.frame.origin.y accordingly.
var keyboardHeight: CGFloat = 100 {
didSet {
let height = UIScreen.main.bounds.height
let menu = self.view.frame.height
let keyb = self.keyboardHeight
self.view.frame.origin.y = height-menu-keyb-20
}
}
...
...
...
#objc func keyboardChange(sender: Notification) {
guard let userInfo = sender.userInfo else { return }
let endFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
keyboardHeight = endFrame?.height ?? 100
}
It's like. You open keyboard and change alert position.
var alertController = UIAlertController(title: nil, message: nil, preferredStyle: UIAlertController.Style.alert)
var alertControllerPositon:CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
#IBAction func showAlert(sender: AnyObject) {
let alertController = UIAlertController(title: "Hello, I'm alert! \n\n\n\n\n\n\n", message: "", preferredStyle: .alert)
let rect = CGRect(x: 15, y: 15, width: 240, height: 150)//CGRectMake(15, 50, 240, 150.0)
let textView = UITextView(frame: rect)
textView.font = UIFont(name: "Helvetica", size: 15)
textView.textColor = UIColor.lightGray
textView.backgroundColor = UIColor.white
textView.layer.borderColor = UIColor.lightGray.cgColor
textView.layer.borderWidth = 1.0
textView.text = "Enter message here"
textView.delegate = self
alertController.view.addSubview(textView)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let action = UIAlertAction(title: "Ok", style: .default, handler: { action in
let msg = (textView.textColor == UIColor.lightGray) ? "" : textView.text
print(msg!)
})
alertController.addAction(cancel)
alertController.addAction(action)
self.present(alertController, animated: true, completion: {
textView.becomeFirstResponder()
})
alertControllerPositon = alertController.view.frame.origin.y
}
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
alertControllerPositon = alertController.view.frame.origin.y
let result = self.view.frame.height - (alertController.view.frame.height + alertController.view.frame.origin.y) - 20
self.alertController.view.frame.origin.y -= (keyboardSize.height - result)
}
}
#objc func keyboardWillHide(notification: NSNotification) {
if self.alertController.view.frame.origin.y != alertControllerPositon {
self.alertController.view.frame.origin.y = alertControllerPositon
}
}