I have converter application with tableView with cells which contains results of conversion.
For example you entered 5 kilometers and in tableView cells for Meters shows 5000 and so on.
I want to make UIAlert with full result when press to one of cells.
So i want to se my result for Meters and i press on meters cell. How could i make it?
I tried to make a additional variables and connect them to Alert but the value still shows not the cell that i choose but the first cell at the table that shows at the moment...
Does anyone have ideas?
let cell1 = tableView.dequeueReusableCell(withIdentifier: "resultCell") as! ResultTableViewCell
let item = converter[indexPath.row]
cell1.nameResult.text = item.title
cell1.subtitleResult.text = item.subtitle
//MARK: - Форматтер для результатов
let formatter = NumberFormatter()
formatter.locale = Locale.current
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 3
formatter.maximumFractionDigits = maxdigits
if converterVal == NSLocalizedString("Километр", comment: "") {
cell1.labelResult.text = formatter.string(from: NSDecimalNumber(value: inputValue).multiplying(by: NSDecimalNumber(value: item.kfKilometer)))
resultVar = cell1.labelResult.text!
resultName = cell1.nameResult.text!
return cell1
} else if converterVal == NSLocalizedString("Метр", comment: "") {
cell1.labelResult.text = formatter.string(from: NSDecimalNumber(value: inputValue).multiplying(by: NSDecimalNumber(value: item.kfMeter)))
resultVar = cell1.labelResult.text!
resultName = cell1.nameResult.text!
return cell1
} else {
cell1.labelResult.text = formatter.string(from: NSDecimalNumber(value: 0))
return cell1
}
nameResult - is name of converted value
and labelResult - is result of conversion
and for every cell i have if else statement.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == self.tableView2 {
let alertController = UIAlertController(title: NSLocalizedString("\(inputValue) \(detailLabel) is:", comment: ""), message: NSLocalizedString("\(resultVar) \(resultName)", comment: ""), preferredStyle: .alert)
let OKAction = UIAlertAction(title: NSLocalizedString("Спасибо", comment: ""), style: .default) { action in
// ...
}
alertController.addAction(OKAction)
self.present(alertController, animated: true) {
// ...
}
}
// tableView.deselectRow(at: indexPath, animated: true)
}
And i want to show more closely this labels in Alert but only for every cell it must be own...
May be you need to modify you method like below
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == self.tableView2 {
// get your selected row data
let item = converter[indexPath.row]
//use item.title or item.subtitle instead of label
let alertController = UIAlertController(title: NSLocalizedString("\(inputValue) \(detailLabel) is:", comment: ""), message: NSLocalizedString("\(resultVar) \(resultName)", comment: ""), preferredStyle: .alert)
let OKAction = UIAlertAction(title: NSLocalizedString("Спасибо", comment: ""), style: .default) { action in
// ...
}
alertController.addAction(OKAction)
self.present(alertController, animated: true) {
// ...
}
}
}
Let me explain something : cellForRowAt indexPath this method create cell and fill data whatever you pass in it. so if you assign value resultVar in this method, it will give you wrong value.
didSelectRowAt called when you click on cell row, so assign value resultVar in this method and do your operations or whatever you want
Access cell instead when you click on row
if let cell = tableView.cellForRow(at: indexPath) as? YourCellClass {
// access your cell label and get values
print(cell.titleLable.text!)
}
Related
I'm developing an iOS app where I want to reload information of a UITableView from a different controller. In order to do that, I have a reference of the controller MainViewController with the UITableView in another controller called (AirlinesController).
I have an issue reloading the data of the UITableView of the first controller where it messes up pretty much:
MainViewController
Each cell of the table you can see leads to AirlinesController:
AirlinesController
So after the user clicks on the "Apply" button, the UITableView of MainViewController reloads using mainView.reloadData(). In this example I would want to see in the MainViewController that the cell with the title "Embraer" has a green label with the text "Completed" and the cell with the title "Airbus" has a yellow label with the title "Employee" but this is the result I get after reloading the table:
Why did the last cell of the table change one of its labels color to yellow?
This is the code I'm using:
MainViewController
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! CellController
let items = self.gameView.data!.levels
cell.model.text = items[indexPath.row].name
if items[indexPath.row].id < self.gameView.game!.level.id {
cell.cost.text = "Complete"
cell.cost.textColor = UIColor.systemGreen
cell.accessoryType = .none
cell.isUserInteractionEnabled = false
} else if items[indexPath.row].id == self.gameView.game!.level.id {
cell.cost.text = "Employee"
cell.cost.textColor = UIColor.systemYellow
cell.accessoryType = .none
cell.isUserInteractionEnabled = false
} else {
cell.cost.text = "\(items[indexPath.row].XP) XP"
}
return cell
}
AirlinesController
#IBAction func apply(_ sender: Any) {
if (mainView.game.XP >= level.XP) {
let new_salary = Int(Float(mainView.game.salary) * level.salaryMultiplier)
let new_XP = Int(Float(mainView.game.XPSalary) * level.XPMultiplier)
mainView.game.salary = new_salary
mainView.game.XPSalary = new_XP
mainView.salaryLabel.text = "\(new_salary) $"
mainView.XPLabel.text = "\(new_XP) XP"
mainView.workingFor.text = "Currently working for \(level.name)"
mainView.game.level = Level(id: level.id, name: level.name, XP: 0, XPMultiplier: 1, salaryMultiplier: 1, aircrafts: [Aircraft]())
mainView.saveGame()
DispatchQueue.main.async {
self.mainView.levelItems.reloadData()
self.navigationController?.popViewController(animated: true)
}
} else {
let alert = UIAlertController(title: "Error", message: "Not enough experience to apply!", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.cancel, handler: nil))
self.present(alert, animated: true)
}
}
How can I fix this?
This is because of the reuse of cells.
Set the default color in else condition.
} else {
cell.cost.textColor = UIColor.gray
cell.cost.text = "\(items[indexPath.row].XP) XP"
}
Another way, you can set the default style property inside the prepareForReuse method of UITableViewCell
class TableViewCell: UITableViewCell {
override func prepareForReuse() {
super.prepareForReuse()
// Set default cell style
}
}
TableViewCell are reused all the time. My advice is that you have to set the default color every time.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! CellController
cell.cost.textColor = ...your default text color....
...
return cell
I have a UITableView with 2 sections, in the first one there is the cells that each represent the different item from an array, and the second one calls a UIAlertController with a textfield. I want whatever I write in the textfield to show in the first section of the tableView. My code currently is:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.section {
case 0:
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
UserDefaults.standard.set(selectedCaseSolutionsForCell[indexPath.row], forKey: "ollShowAlg\(selectedCaseID)")
print("OLL Case with ID \(selectedCaseID) had its main algorithm changed to \(selectedCaseSolutionsForCell[indexPath.row])")
let newMainSolve : String = UserDefaults.standard.string(forKey: "ollShowAlg\(selectedCaseID)")!
print("THE ALGORITHM IS NOW \(newMainSolve)")
case 1:
tableView.cellForRow(at: indexPath)?.accessoryType = .none
let alert = UIAlertController(title: "Add New Algoritm", message: "", preferredStyle: .alert)
alert.addTextField()
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
print("Text field: \(textField!.text!)")
}))
present(alert, animated: true)
default:
return
}
}
How can I add the textfield input to the array and then show that at the end of the UITableView? This question is not a duplicate as I'm not using a custom cell and don't have an IBOutlet or IBAction for it.
I'll assume the table's data source is an array of string named data. Something like this:
fileprivate var data: [String] = []
Then all you have to do after this line print("Text field: \(textField!.text!)") is add the following:
self.table.beginUpdates()
self.data.append(textField!.text!)
self.table.insertRows(at: [IndexPath(item: self.data.count - 1, section: 0)], with: .bottom)
self.table.endUpdates()
My code is this:
let alrController = UIAlertController(title: "Membri", message: nil, preferredStyle: UIAlertControllerStyle.actionSheet)
tableView.backgroundColor = UIColor.white
alrController.view.addSubview(tableView)
let cancelAction = UIAlertAction(title: "Esci", style: UIAlertActionStyle.cancel, handler: {(alert: UIAlertAction!) in})
alrController.addAction(cancelAction)
self.present(alrController, animated: true, completion:{})
I want to populate (but I don't know how) the tableView with this values in my array: names["name1","name2","name3"]
Can someone help me?
To populate an action sheet, you don't add a tableView. Instead, you simply add the actions and it will create and manage the tableView privately.
For a recent tutorial, see UIAlertController Examples
The idea is that you'd create an UIAlertAction for each String in your array, including a closure for what to do when user taps that action row.
for name in names
{
let namedAction = UIAlertAction(title: name, style: .default)
{ (action) in
// do something when this action is chosen (tapped)
}
alrController.addAction(namedAction)
}
You need to implement the following tableView dataSource methods in order to populate this data and also set tableView datasource to alertController like below:-
tableView.dataSource = alertController
TableView DataSource method
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell: yourCustomCell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as? yourCustomCell
else {
fatalError("yourCustomCell not found")
}
cell.textLabel.text = names[indexpath.row]
return cell
You can use custom UIViewController transition to achieve this kind of functionality.
This link: https://github.com/pgpt10/Custom-Animator will give you an idea of how you can achieve that.
Good day to all. Faced a problem. I need to make a table with a button and by clicking on the button I get a alert with the number of the cell. The table cells themselves are not active. That's how I realized it. When I scroll the table in the beginning everything is fine, when you press the button, a alert is displayed with the correct line number, but after 4 elements an error appears.
This error appears in the line where I'm working with the 4 tag.
Fatal error: unexpectedly found nil while unwrapping an Optional value
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as UITableViewCell
if (tableView.tag == 1) {
let numLabel: UILabel = tableView.viewWithTag(3) as! UILabel
numLabel.text = String(indexPath.row)
} else if (tableView.tag == 2) {
//Error appears here
let numButton: UIButton = tableView.viewWithTag(4) as! UIButton
numButton.setTitle(String(indexPath.row), for: .normal)
numButton.tag = indexPath.row
}
return cell
}
#IBAction func showAlertForRow(row: UIButton) {
let alert = UIAlertController(title:"Test work",message:"Cell at row \(row.tag) was tapped!",preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
What you are designing for implementing this procedure is not correct. What you can do
Make a custom cell
Add a button in custom cell
Add action in that button in CellForRowAtIndexPath
Handle action from ViewController where you added tableView.
I made a whole project for you.Just to let you know. if you want to add customCell in tableView you need to register it like this in viewDidLoad.
i have done is in ViewController.swift file. check out my project.
let nib = UINib.init(nibName:String(describing: sampleTableViewCell.self) , bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "chatCell")
Then check cellForRowAtIndexPath function:
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "chatCell", for: indexPath) as! sampleTableViewCell
cell.clickMeBtn.tag = indexPath.row
cell.clickMeBtn.addTarget(self, action: #selector(onButtonPressed(sender :)), for: .touchUpInside)
return cell
}
Button press function:
func onButtonPressed(sender:UIButton) {
let alert = UIAlertController.init(title:"Cell index is"+String(sender.tag), message: nil, preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction.init(title: "ok", style: UIAlertActionStyle.default) { (UIAlertAction) in
}
alert.addAction(okAction)
self.present(alert, animated: true, completion: nil)
}
Check only three files:
Github link
ViewController.swift
sampleTableViewCell.swift
sampleTableViewCell.xib**
Here is the output:
I have a tableView in a view controller where I display data from an API call, now if the user selects a tableview cell(say row 2 in the TableView), I want to fetch that data(Data in row 2 of TableView) and display it in the Textfield on the same screen. What is the best way to do this?
The simplest way is you can show show the UIAlertController with textField on didSelect of tableViewCell.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let alert = UIAlertController(title: "Edit Data", message: "Edit corresponding detail", preferredStyle: .alert)
alert.addTextField { (textField) in
textField.placeholder = "Enter name"
textField.text = yourArray[indexPath.row]
}
alert.addAction(UIAlertAction(title: "Edit", style: .default, handler: { (action) in
//Edit data on array
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true)
}
You can try this one, When user select's particular UITableViewCell then that cell contents will be show in UITextField.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell= tableView1.cellForRow(at: indexPath)
if let txtVal = cell?.textLabel?.text {
textField.text = txtVal
}
}
You have data from from webservice which you are displaying on your UITableview say arrWebServiceData. and you have index of row where user clicked on say index. Simplest way is to get Data from arrWebServiceData at index and use it to display on test field.
for example:
NSArray *arrWebServiceData; //you are storing data from Wevserice here.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let index = indexPath.row;
let dataAtIselectedIndex = yourArray[indexPath.row] ;
//If data is string, dirctly display it on text field,or if its dictionary, set object of diction on your text field.
}