Picker Value into tableView swift - ios

The first text field is a Int Value where you insert your current sold. A second one textfield where I get some Int value and add to a tableView with a button. The value you add into the second textfield soustract to the main value ( in that case 2500 ). That's working great.
My problem is to attribuate the PickerValue to the TableRow Value. it's working but not like I want.
I want to save the pickerValue when i click onto the button. But when i enter a new value it's changing all row of the pickerValue. In that case, you can see two row with "telephone". Normaly it's would be "telephone" and something else ( "maison" or "house").
Do you see a reason why it's doing like this ? I wish you can understand what i mean.
problem with picker value save into table view (gif)
#IBAction func addBtn(_ sender: Any) {
view.endEditing(true)
salaire = Int(salaireLabel.text!) ?? 0
valeur = Int(ressourceTextField.text!) ?? 0
if String(valeur) != "" {
addBtnActivated = true
restValueLabel.textColor = UIColor.blue
arrayRessource.append(valeur)
// modifie automatiquement le salaire
restValueLabel.text = String(soustraction)
tableRessourceOT.reloadData()
// reset le champs
ressourceTextField.text = ""
picker.selectRow(0, inComponent: 0, animated: true)
}
}
Here is some code I'm using. I'm thinking the problem came from the tableview Func
var arrayPickerValue: [String] = ["", "maison", "telephone"]
// ------------------------------ START PICKER ------------------------------------
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
print("-----arraypicker.count------")
print(arrayPickerValue.count)
return arrayPickerValue.count
}
// hauteur du picker pour que les images ne se supperpose pas / Picker height
func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return 25
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
print("----arraypicker[row]----")
print(arrayPickerValue[row])
return arrayPickerValue[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
stored = arrayPickerValue[row]
print("-----stored dans func didselectrow------")
print(stored as Any)
}
//-------------------------- END PICKER -----------------------------------
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let row = indexPath.row
let value = arrayRessource[row]
cell.textLabel?.text = "- " + String(value) + " €"
// cell.detailTextLabel?.text =
updateRestLabel()
setRestLabel()
return cell
}
Here is my outlet :
#IBOutlet weak var tableRessourceOT: UITableView!
Then my arrayRessource :
var arrayRessource: [Int] = [] {
didSet {
if oldValue != arrayRessource {
userDefault.setValue(arrayRessource, forKey: arrayKey)
}
}
}
and call with the function :
func getArray() {
if let newArray = userDefault.array(forKey: arrayKey) as? [Int] {
arrayRessource = newArray
}
}

Your question is not very clear.
However I will make an attempt to offer some help from what I can extract from your code.
I assume restValueLabel is not something within your cells? It is probably the green label "2500" in your screenshot?
If that is the case, don't set it in cellForRow(at:). This method is called every time a cell becomes visible and should only be used to configure that very cell based on your data source (arrayRessource).
Instead create a method updateRestValueLabel() that iterates your data source, does the calculation and sets the appropriate value to your restValueLabel. Call that method every time your data source changes, so along with tableRessourceOT.reloadData().
There are also some stylistic issues with your code (e.g. avoid force unwrapping ! unless you have good reason to use it) but this is out of scope here.

The problem come from my array was an Int array and my pickerValue was String array.
Array can't be String array's and Int array's.
var arrayRessource: [String] = [] {
didSet {
if oldValue != arrayRessource {
userDefault.setValue(arrayRessource, forKey: arrayKey)
}
}
}
Thanx for your advice by the way i'm progressing and doing my best

Related

UIPickerView where selected 1st component decides contents of 2nd component is out of sync

I have encountered some synchronisation/graphic update problems with my UIPickerView.
I want a view with 2 components, where the content of the second component depends on the selected row of the first component.
My code is inspired from: Swift UIPickerView 1st component changes 2nd components data
However, while it seems to work, sometimes (not every time) there are some visual problems, as seen on the screenshots below. (on the second screenshot, you can see that the rows of the second component are not really correct, and are a mix of the rows from the first and the second component)
Here is the code:
import UIKit
class AddActivityViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var typePicker: UIPickerView!
var pickerData: [(String,[String])] = []
override func viewDidLoad() {
super.viewDidLoad()
self.typePicker.delegate = self
self.typePicker.dataSource = self
pickerData = [("sport",["bike", "run", "soccer", "basketball"]),
("games",["videogame", "boardgame", "adventuregame"])]
// not sure if necessary
typePicker.reloadAllComponents()
typePicker.selectRow(0, inComponent: 0, animated: false)
// pickerData = [("sport",["bike", "run", "soccer"]),
// ("games",["videogame", "boardgame", "adventuregame"])]
}
// number of columns in Picker
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
// number of rows per column in Picker
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
print("function 1 called")
if component == 0 {
return pickerData.count
} else {
let selectedRowInFirstComponent = pickerView.selectedRow(inComponent: 0)
return pickerData[selectedRowInFirstComponent].1.count
}
}
// what to show for a specific row (row) and column (component)
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
print("function 2 called with values: component: \(component), row: \(row)")
if component == 0 {
// refresh and reset 2nd component everytime another 1st component is chosen
pickerView.reloadComponent(1)
pickerView.selectRow(0, inComponent: 1, animated: true)
// return the first value of the tuple (so the category name) at index row
return pickerData[row].0
} else {
// component is 1, so we look which row is selected in the first component
let selectedRowInFirstComponent = pickerView.selectedRow(inComponent: 0)
// we check if the selected row is the minimum of the given row index and the amount of elements in a given category tuple array
print("---",row, (pickerData[selectedRowInFirstComponent].1.count)-1)
let safeRowIndex = min(row, (pickerData[selectedRowInFirstComponent].1.count)-1)
return pickerData[selectedRowInFirstComponent].1[safeRowIndex]
}
//return pickerData[component].1[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
// This method is triggered whenever the user makes a change to the picker selection.
// The parameter named row and component represents what was selected.
}
}
Is this a problem with my code or generally a complicated aspect of UIPickers that can not be trivially solved?
Additionally, is there a nicer way to develop this functionality?
I solved the error, however I do not understand why this solves it.
The solution is to imlement the func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)method, which I did not believe to be necessary just to show the fields.
In other words, just add this to my existing code:
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if component == 0 {
pickerView.reloadComponent(1)
} else {
let selectedRowInFirstComponent = pickerView.selectedRow(inComponent: 0)
print(pickerData[selectedRowInFirstComponent].1[row])
}
}

How to differentiate between instances of the same view in prototyped UITableViewCells

I'm using a UITableViewCell prototype that contains a UIPickerView and use that prototype for 4 different cells with 4 different PickerView in the tableView. I use the following code to supply the cell to tableView (tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) and to set each picker to a different instance variable in order to differentiate between the pickers later (since the same UITableViewController instance is the delegate/datasource for all of them, for example).
However, when running the code, all 4 instance variables end up pointing to the same UIPickerView. How can I ensure that it uses 4 distinct UIPickerViews instead?
func PickerCell(tableView: UITableView, indexPath: NSIndexPath, inout picker: UIPickerView?) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PickerCell")
if let pickerFromCell = cell?.contentView.viewWithTag(1) as? UIPickerView {
pickerFromCell.reloadAllComponents()
pickerFromCell.dataSource = self
pickerFromCell.delegate = self
picker = pickerFromCell
}
return cell!
}
Instead of using tag try something like this. Change your didSelectRow of PickerViewDelegate like this
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let cell = imageView.superview?.superview as! UITableViewCell //You have to use as may super as your UITableViewCell hierarchy
let indexPath = self.tabelView.indexPathForCell(cell)
self.pickerSelectedIndexArr[indexpath.row] = row
}
Also add pickerSelectedIndexArr array in your file and assign it in viewDidLoad like following way
var pickerSelectedIndexArr: [Int] = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
self.pickerSelectedIndexArr = [0, 0, 0 ,0]
}
Now you can easily get all the picker selected value any time you want
Hope this will help you.
var dict: [Int, UIPickerView]
...
if dict[indexPath.row] == nil {
// Create UIPickerView and assign it to dict[indexPath.row].
}
As this question is tagged with Objective C, I am giving your answer in OBJC.
Here is what you can do, to deal with controls in reusable cell,
Tip for solving such problem, when you have controls in UICollectionViewCell or UITableViewCell, give tag to your controls depending upon your indexPath.
Giving example with collectionViewCell you can do it with tableViewCell
case 1 : If CollectionView is sectional, then your tags will be like [0][0], [1][0] ... In such case do something like this,
collectionViewCell.picker.tag = [[NSString stringWithFormat:#"%ld%ld",(long)indexPath.section,(long)indexPath.item] intValue]; // If it is sectional collection view
case 2 : If Collection View is non-sectional,do something like this,
collectionViewCell.picker.tag = [[NSString stringWithFormat:#"%ld",(long)indexPath.item] intValue]; // If it is non-sectional collection view
Hope this will solve your problem or give you idea to manage accordingly.
If you have more than one control in your cell then just give tags like indexPath.item + 1 + 2 ...
I agree with Nirav, that you should use the cell to determine the NSIndexPath of the cell in question.
Personally, I'd make the cell subclass the data source and delegate of the picker and have it take responsibility for the picker. This completely eliminates any confusion about what picker is associated with which cell. But I'd have a protocol by which the cell can inform the view controller when the user selected a value from the picker and the view controller can update the model.
For example, consider this UITableViewCell subclass:
// CustomCell.swift
import UIKit
/// Protocol that the view controller will conform to in order to receive updates
/// from the cell regarding which row in the picker was picked.
///
/// - note: This is a `class` protocol so that I can use `weak` reference.
protocol CustomCellDelegate: class {
func cell(customCell: CustomCell, pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
}
/// Custom cell subclass, which is the picker's data source and delegate
class CustomCell: UITableViewCell, UIPickerViewDataSource, UIPickerViewDelegate {
/// The delegate who we will inform of any picker changes.
///
/// This is weak to avoid strong reference cycle.
weak var delegate: CustomCellDelegate?
/// The array of values to be shown in the picker.
///
/// If the `values` changes, this reloads the picker view.
var values: [String]? {
didSet {
pickerView.reloadComponent(0)
}
}
/// The outlet to the picker in the cell.
#IBOutlet weak var pickerView: UIPickerView!
// MARK: UIPickerViewDataSource
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return values?.count ?? 0
}
// MARK: UIPickerViewDelegate
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return values?[row] ?? ""
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
delegate?.cell(self, pickerView: pickerView, didSelectRow: row, inComponent: component)
}
}
And then the view controller:
// ViewController.swift
import UIKit
class ViewController: UITableViewController, CustomCellDelegate {
// an array of arrays of acceptable values
let troupes = [
["Mo", "Larry", "Curly"],
["Abbott", "Costello"],
["Groucho", "Harpo", "Zeppo", "Chico", "Gummo"],
["Laurel", "Hardy"],
["Graham Chapman", "John Cleese", "Terry Gilliam", "Eric Idle", "Terry Jones", "Michael Palin"]
]
/// An array that indicates which is item is selected for each table view cell
var selectedItemForRow: [Int]!
override func viewDidLoad() {
super.viewDidLoad()
selectedItemForRow = troupes.map { _ in return 0 } // initialize the `selectedItemForRow` array with zeros
// Whatever further initialization of the view controller goes here.
}
// MARK: UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return troupes.count
}
// Populate cell, setting delegate, list of acceptable values, and currently selected value.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as! CustomCell
cell.delegate = self
cell.values = troupes[indexPath.row]
cell.pickerView.selectRow(selectedItemForRow[indexPath.row], inComponent: 0, animated: false)
return cell
}
// MARK: CustomCellDelegate
// When the cell tells us that the user changed the selected row, let's update our model accordingly.
func cell(customCell: CustomCell, pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if let indexPath = tableView.indexPathForCell(customCell) {
selectedItemForRow[indexPath.row] = row
}
}
}

Update Label by using pickerview and text field

I have a PickerView that deposit values. This values will be calculate with a user textfield input. The result will show in a label. That works for me.
By starting the app the textfield have a fix number of 1.
How can I now update my label automatically by use the Pickerview?
I read and try many things but it don´t works.
Maybe it is a little thing, but i don´t see it.
import UIKit
class BalkenbewehrungVC: UIViewController, UIPopoverPresentationControllerDelegate, UIPickerViewDataSource, UIPickerViewDelegate, UITextFieldDelegate {
// Deklarationen Pickerview
var multiplicator : Double = 0.0
let multiplicators = [0.0,6.0,8.0,10.0,12.0,14.0,16.0,20.0,25.0,26.0,28.0,30.0,32.0,36.0,40.0,50.0]
let PI = 3.1415
// Pickerview füllen
var pickerDataSource = ["---","Ø 6","Ø 8","Ø 10","Ø 12","Ø 14","Ø 16","Ø 20","Ø 25","Ø 26","Ø 28","Ø 30","Ø 32","Ø 36","Ø 40","Ø 50"]
// Picker im aktivieren
#IBOutlet weak var Pickerview: UIPickerView!
// Ausgabewert As = xxxx cm
#IBOutlet var AusgabePicker: UILabel!
// Eingabe Anzahl Stäbe
#IBOutlet var AnzahlStab: UITextField!
#IBAction func test(sender: UITextField) {
if AnzahlStab.text!.isEmpty {
AnzahlStab.text = "1"
let result1 = (multiplicator / 10) * (multiplicator / 10) * PI / 4 * 1
AusgabePicker.text! = String(format:"%.3f", result1)
} else {
let result = (multiplicator / 10) * (multiplicator / 10) * PI / 4 * (AnzahlStab.text! as NSString).doubleValue
// let resultString = "\(result)"
AusgabePicker.text = String(format:"%.3f", result)
}
}
// Picker - feste Reihen
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
// Picker - Aufaddierung neuer Reihen
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerDataSource.count
}
// Picker - Datenübernahme multiplicator in Picker
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerDataSource[row]
}
// Picker - Wertefestlegung Picker
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
multiplicator = multiplicators[row]
_ = NSNumberFormatter.localizedStringFromNumber(NSNumber(double: multiplicator), numberStyle:.DecimalStyle)
}
In the didSelectRow method for the pickerView, set the label's text to your newly calculated value.
Update: To update the label's text depending on the textField's input, inside your ViewController's viewDidLoad method, add this line
AnzahlStab.delegate = self
and then add the textFieldDidEndEditing method, and inside it update the label's text to the new value. This method is called when you are done with editing the text field.
Need to call function test in picker view didSelectRow. Or Simply Replace your didSelectRow with following code.
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
multiplicator = multiplicators[row]
_ = NSNumberFormatter.localizedStringFromNumber(NSNumber(double: multiplicator), numberStyle:.DecimalStyle)
self.test(AnzahlStab)
}
Hope this Answer will help you.

PickerView - How to return 2 different array based on a segmented Control selection

In my app I have a text field (Distance) that has segmented control to choose the unit reference (Km/Mi):
I have another text field (pace) that show a UIPickerView. This picker view can be populated with 2 arrays based on what unit the user selected. Everything works except that, even when the picker view is not shown and I change the selection, the array change only when I start scroll the picker view. So initially it shows the array in km even if I selected Mi and then it changes when I start moving the picker.
Initially I set a variable for the unit reference and the 2 arrays
var unitReference = "Km" // this is the initial selection on the segmented control
let paceKmArray = [" ", "Relaxing(less than 15km/h)", "Easy(15km/h-20km/h)","Medium(20km/h-25km/h)","Nice(25km/h-30km/h)","Fast(30km/h-35km/h)", "Very Fast(>35km/h)"]
let paceMiArray = [" ", "Relaxing(less than 10 mi/h)", "Easy(10mi/h-13mi/h)","Medium(13mi/h-16mi/h))","Nice(16mi/h-19mi/h))","Fast(19mi/h-12mi/h))", "Very Fast(>22mi/h)"]
then in viewDidLoad
unitReferenceSegmentedControl.addTarget(self, action: "unitChanged:", forControlEvents: .ValueChanged);
which call this method to changed the unit reference
func unitChanged(sender:UISegmentedControl){
if sender.selectedSegmentIndex == 0{
unitReference = "Km"
print(unitReference)
}
if sender.selectedSegmentIndex == 1{
unitReference = "Mi"
print(unitReference)
}
}
And the picker view methods
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if pickerView.tag == 0{
return rideTypeArray[row]
}
if pickerView.tag == 1{
if unitReference == "Km"{
return paceKmArray[row]
}
if unitReference == "Mi"{
return paceMiArray[row]
}
}
return ""
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int{
if pickerView.tag == 0{
return rideTypeArray.count
}
if pickerView.tag == 1{
if self.unitReference == "Km"{
return paceKmArray.count
}
if self.unitReference == "Mi"{
return paceMiArray.count
}
}
return 0
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
if pickerView.tag == 0{
rideTypeTextField.text = rideTypeArray[rideTypePickerView!.selectedRowInComponent(0)] as String
}
if pickerView.tag == 1{
if unitReference == "Km"{
paceTextField.text = paceKmArray[pacePickerView!.selectedRowInComponent(0)] as String
}
if unitReference == "Mi"{
paceTextField.text = paceMiArray[pacePickerView!.selectedRowInComponent(0)] as String
}
}
}
I am not sure this is the best way to do it. If there is a more elegant way to do it, I will be more than happy to learn it.
You are not seeing the changes in your picker view because you are not reloading the data after the datasource is changed. Just call reloadAllComponents on your pickerView once you have changed the datasource and you are good to go.
func unitChanged(sender:UISegmentedControl) {
//Your previous code for changing the datasource array.
//Now reload the UIPickerView
pacePickerView.reloadAllComponents()
}
One more suggestion i would like to give is that if in both the datasource array's have same set of key value pairs then you should keep a 3rd array as the ultimate datasource and switch it with the respective arrays from your unitChanged: method. That way you won't need to have an if condition every now and then to get the current set of data.

Use selected UIPicker row as text for custom UITableViewCell UILabel SWIFT

I have been banging against this for days now, trying a number of different approaches. I have a UITableView with custom cells containing two UILabels. On selecting the cell, a UIPicker is revealed, and a variable is set referencing which cell was tapped.
Once a selection is made in the UIPicker, I need to take that value and use it to replace the existing .text of one of the cell labels. I have tried using .viewWithTag a few different ways (first tagging the label itself, then the entire cell) and nothing works.
My didSelect for the picker is:
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
println("pickerView did select row \(row)")
if(self.getStatus() == "newFirst"){
switch (editingField){
case 0:
var l:NewOrderCell! = tableView.viewWithTag(editingField) as? NewOrderCell
//the label in the custom cell is called 'Text'
l.Text.text = pickerData[row]
println("should be changing \(l.Text.text) into \(pickerData[row])")
default:
var l:NewOrderCell! = tableView.viewWithTag(editingField) as? NewOrderCell
l.Text.text = pickerData[row]
}
}
picker.hidden=true
}
and my cellForRowAtIndexPath for the table is:
var cell:NewOrderCell = tableView.dequeueReusableCellWithIdentifier("NewOrderCell") as NewOrderCell
//label
cell.Label.text = self.newOrder[indexPath.row]
//text
cell.Text.text = "Please Select"
cell.tag = indexPath.row
return cell
I know my goal, but can't get a handle on the proper way to reference a cell within a table from another method. Thanks for your help
I have come up with a solution that works, but I feel is inelegant and hard to maintain: when the picker row is selected, that text is written to the array that was used to originally populate the table (overwriting the original item), and then I reload the table, so that the new value appears. So, it's something like this:
var truth: [String:String] = ["Key1":"","Key2":"","Key3":""]
var keys:[String] = ["Key1", "Key2","Key3"]
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:NewOrderCell = tableView.dequeueReusableCellWithIdentifier("NewOrderCell") as NewOrderCell
//label
cell.Label.text = keys[indexPath.row]
//textfield
if(truth[keys[indexPath.row]] == ""){
cell.Text.text = "Please Select"
}
else{
cell.Text.text = truth[keys[indexPath.row]]
}
return cell
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
truth[keys[editingField]] = pickerData[row]
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
}
Happy to hear better solutions

Resources