I tried a lot but it just shows me "?" in the rows of the four components.
Is it possible to put a String at the first place in the Array Like as titles for the 4 components? I had the idea to change all the Integers in the arrays into Strings but it would takes me too long...
let componentOne = [1...1000]
let componentTwo = [1...59]
let componentThree = [1...59]
let componentFour = [1...3]
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 4
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0 {
return 1000
}
if component == 1 {
return 59
}
if component == 2 {
return 59
}
if component == 3 {
return 3
}
return component
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> Int {
if component == 0 {
let row = componentOne[row]
return 1000
}
if component == 1 {
let row = componentTwo[row]
return 59
}
if component == 2 {
let row = componentThree[row]
return 59
}
if component == 3 {
let row = componentFour[row]
return 10
}
return row
}
```
You can't just change the delegate method. This is the correct one:
func pickerView(_ pickerView: UIPickerView,
titleForRow row: Int,
forComponent component: Int) -> String?
You have:
func pickerView(_ pickerView: UIPickerView,
titleForRow row: Int,
forComponent component: Int) -> Int
You must return a String? no matter what -- if you change the function's return type to Int, it doesn't match the protocol requirement.
The good thing is that you can easily make a String from an Int. Just use String interpolation like this:
/// Inside pickerView(_:titleForRow:forComponent:)
let row = componentOne[row]
return "\(1000)"
}
Related
I have two (or more) text fields in an app, and I want each textField to pop up its own Pickerview wheel when selected... Here's what I've got so far:
var pickerView = UIPickerView()
#IBOutlet weak var serviceType: UITextField!
#IBOutlet weak var brandsField: UITextField!
var serviceArray = ["Services", "..."]
var brandsArray = ["Apple", "Samsung"]
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
}
func updatePicker(){
self.pickerView.reloadAllComponents()
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if serviceType.isFirstResponder{
return serviceArray.count
} else if brandsField.isFirstResponder{
return brandsArray.count
}
} //ERROR HERE
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if serviceType.isFirstResponder{
return serviceArray[row]
}else if brandsField.isFirstResponder{
return brandsArray[row]
}
} //ERROR HERE
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if serviceType.isFirstResponder{
let itemselected = serviceArray[row]
serviceType.text = itemselected
}else if brandsField.isFirstResponder{
let itemselected = brandsArray[row]
brandsField.text = itemselected
}
}
}
but it keeps giving me the error saying "Missing return in a function expected to return String?" and "Missing return in a function expected to return int" at where I've Commented. What can I do?
You can use this UITextField subclass if you want to use multiple textfields with pickerview.
class PickerTextField: UITextField,UIPickerViewDelegate,UIPickerViewDataSource {
let pickerView = UIPickerView()
var itemList = [String]()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
#objc func textEdited(_ sender:PickerTextField)
{
self.text = itemList[pickerView.selectedRow(inComponent: 0)]
}
override func draw(_ rect: CGRect) {
super.draw(rect)
self.tintColor = UIColor.clear
self.addTarget(self, action: #selector(textEdited(_:)), for: .editingChanged)
pickerView.showsSelectionIndicator = true
pickerView.delegate = self
pickerView.dataSource = self
self.inputView = pickerView
let toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.default
toolBar.isTranslucent = true
toolBar.tintColor = .black
toolBar.sizeToFit()
let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(doneBtnAction(_:)))
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(doneBtnAction(_:)))
toolBar.items = [cancelButton, spaceButton, doneButton]
self.inputAccessoryView = toolBar
}
#objc func doneBtnAction(_ sender:UIBarButtonItem) {
resignFirstResponder()
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return itemList.count
}
func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
let title = itemList[row]
return NSAttributedString(string: title, attributes: [NSAttributedStringKey.foregroundColor:UIColor.black])
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.text = itemList[row]
}
}
And assign the options list in viewDidLoad
class ViewController: UIViewController {
#IBOutlet weak var serviceType: PickerTextField!
#IBOutlet weak var brandsField: PickerTextField!
override func viewDidLoad() {
super.viewDidLoad()
serviceType.itemList = ["Services", "others"]
brandsField.itemList = ["Apple", "Samsung"]
}
}
Assign subclass to textfield.
Result
You need to return the else case.
if serviceType.isFirstResponder{
return serviceArray.count
} else if brandsField.isFirstResponder{
return brandsArray.count
} else {
// insert your else case here
return 0 // for example
}
Refactor these 3 methods to this , as the compiler won't know what to return if all if cases are not hit , so it gives this error
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if serviceType.isFirstResponder{
return serviceArray.count
} else {
return brandsArray.count
}
} //ERROR HERE
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if serviceType.isFirstResponder{
return serviceArray[row]
}else {
return brandsArray[row]
}
} //ERROR HERE
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if serviceType.isFirstResponder{
let itemselected = serviceArray[row]
serviceType.text = itemselected
}else {
let itemselected = brandsArray[row]
brandsField.text = itemselected
}
}
I need a multiple component pickerview, but I need to add a new column to the far left of it. So far it only has two of the three I need. Here is the current code. I have addeded arrays, wrapped an array inside an array, added variables as a column and also changed the outputs.
import UIKit
class Country {
var cats: String
var country: String
var cities: [String]
init(country:String, cities:[String]) {
self.cats = cat
self.country = country
self.cities = cities
}
}
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var pickerView: UIPickerView!
#IBOutlet weak var countryLbl: UILabel!
var countries = [Country]()
override func viewDidLoad() {
pickerView.delegate = self
pickerView.dataSource = self
cats.apppend(Cat(cat: "furry",
countries.append(Country(country: "India", cities: ["Delhi", "Ahmedabad", "Mumbai", "Pune"]))
countries.append(Country(country: "USA", cities: ["New York", "DC", "Fairfax"]))
countries.append(Country(country: "Austrailia", cities: ["Sydney", "Melbourne"]))
super.viewDidLoad()
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 3
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0 {
return countries.count
}
else {
let selectedCountry = pickerView.selectedRow(inComponent: 0)
return countries[selectedCountry].cities.count
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if component == 0 {
return countries[row].country
}
else {
let selectedCountry = pickerView.selectedRow(inComponent: 0)
return countries[selectedCountry].cities[row]
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
pickerView.reloadComponent(1)
let selectedCountry = pickerView.selectedRow(inComponent: 0)
let selectedCity = pickerView.selectedRow(inComponent: 1)
let country = countries[selectedCountry].country
let city = countries[selectedCountry].cities[selectedCity]
countryLbl.text = "Country: \(country)\nCity: \(city)"
}
}
I added the vars but do I add more brackets and then I don't know how to identify the self like why does country = country but cat can't = cat? Also, the first column I'm going to add (far left in the row) will only have 2 choices and won't effect the other choices.
Since the cats component has nothing to do with the countries, do not add cats to your Countries class (which should be a struct, by the way).
Just have a separate cats array in your view controller. And you need to update all of the picker view methods.
struct Country {
let country: String
let cities: [String]
}
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var pickerView: UIPickerView!
#IBOutlet weak var countryLbl: UILabel!
let cats = ["Cat1", "Cat2"]
var countries = [Country]()
override func viewDidLoad() {
pickerView.delegate = self
pickerView.dataSource = self
countries.append(Country(country: "India", cities: ["Delhi", "Ahmedabad", "Mumbai", "Pune"]))
countries.append(Country(country: "USA", cities: ["New York", "DC", "Fairfax"]))
countries.append(Country(country: "Austrailia", cities: ["Sydney", "Melbourne"]))
super.viewDidLoad()
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 3
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0 {
return cats.count
} else if component == 1 {
return countries.count
} else {
let selectedCountry = pickerView.selectedRow(inComponent: 1)
return countries[selectedCountry].cities.count
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if component == 0 {
return cats[row]
} else if component == 1 {
return countries[row].country
} else {
let selectedCountry = pickerView.selectedRow(inComponent: 1)
return countries[selectedCountry].cities[row]
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if component == 0 {
// do something with the new cat
} else if component == 1 || component == 2 {
if component == 1 {
pickerView.reloadComponent(2)
}
let selectedCountry = pickerView.selectedRow(inComponent: 1)
let selectedCity = pickerView.selectedRow(inComponent: 2)
let country = countries[selectedCountry].country
let city = countries[selectedCountry].cities[selectedCity]
countryLbl.text = "Country: \(country)\nCity: \(city)"
}
}
}
I have 4 text fields in a view controller that will use a single PickerView, but update depending on which text field is active (via the editing did begin action). I can load data from a single test array but cannot find a way to have the picker view switch between several arrays that are preloaded with data queried from Parse.
Also, is there a way to reference the array name from a string? Ex: replacing "testArray" with a variable in the didSelectRow function and setting the variable when the text field becomes active.
Thanks!
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if activeField == 1 {
return fieldNameArray[row]
} else if activeField == 2 {
return taskCategoryArray[row]
} else if activeField == 3 {
return assignedPersonArray[row]
} else if activeField == 4 {
return machineUsedArray[row]
}
//return testArray[row]
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if activeField == 1 {
return fieldNameArray.count
} else if activeField == 2 {
return taskCategoryArray.count
} else if activeField == 3 {
return assignedPersonArray.count
} else if activeField == 4 {
return machineUsedArray.count
}
//return testArray.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if activeField == 1 {
fieldNameTextField.text = testArray[row]
} else if activeField == 2 {
taskCategoryTextField.text = testArray[row]
} else if activeField == 3 {
assignedPersonTextField.text = testArray[row]
} else if activeField == 4 {
machineryUsedTextField.text = testArray[row]
}
pickerView.isHidden = true
}
I don't understand the second part of your question.
But for the first part, you are almost there, you just gotta reload the pickerview when one of your textviews becomes active:
pickerView.reloadAllComponents()
all i want to do is change the values of min avg and max based on what the user selected in the picker menu so that i can use them in the MinC AvgC and MaxC label calculation. for example, if user selected a1 then min = 10, avg = 15, and max = 20, but if user selects a2 i want min to = 20, avg = 25, and max = 30. please help and thank you. your time, effort, and support are appreciated. bellow is my code which is currently working without any errors:
class ViewController: UIViewController, UIPickerViewDelegate, UITextFieldDelegate{
#IBOutlet var PLabel: UILabel!
#IBOutlet weak var C: UITextField!
#IBOutlet var MinC: UILabel!
#IBOutlet var AvgC: UILabel!
#IBOutlet var MaxC: UILabel!
var min = 0
var avg = 0
var max = 0
var P = ["a1","a2","a3","a4"]
var CFiller = ["0"]
override func viewDidLoad()
{super.viewDidLoad()
PLabel.text = P[0]
MinC.text = CFiller[0]
AvgC.text = CFiller[0]
MaxC.text = CFiller[0]
C.keyboardType = UIKeyboardType.NumberPad}
override func didReceiveMemoryWarning()
{super.didReceiveMemoryWarning()}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int
{ return 1}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{return P.count}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{return P[row]}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{ var PSelected = P[row]
PLabel.text = PSelected}
#IBAction func CalcButton(sender: AnyObject)
{if let ic = Int (C.text!)
{MinC.text = "\(min * ic)"
AvgC.text = "\(avg * ic)"
MaxC.text = "\(max * ic)"}}
}
Seems to me like you just need to use a switch statement to achieve your goal.
This could look something like this:
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{ var PSelected = P[row]
PLabel.text = PSelected
switch PSelected {
case "a1":
min = 10
avg = 15
max = 20
case "a2":
min = 20
avg = 25
max = 30
...
default:
break
}
}
You could also set it up more efficiently if you desire, like this:
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{ var PSelected = P[row]
PLabel.text = PSelected
var increment = 10
min = 10
avg = 15
max = 20
min += increment*row //if a1, then row == 0, so nothing is added
avg += increment*row
max += increment*row
}
i get data from a web service and my pickerData Array don't save values when i want to use it outside of the Json Parsing bloc.
here's my code
var pickerData: [String] = [String]()
var mag : String!
override func viewDidLoad() {
super.viewDidLoad()
NomMAG.alpha = 0
// \(detectionString)
let str = "http://vps43623.ovh.net/yamoinscher/api/getAllMag"
let url = NSURL(string: str)!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
if let urlContent = data {
do {
let jsonObject = try NSJSONSerialization.JSONObjectWithData(urlContent, options: [])
if let jsonResult = jsonObject as? [String:AnyObject] {
if let Pick = jsonResult["magasin"] as? [[String:String]] {
for categorie in Pick {
self.mag = categorie["libelle"]!
self.pickerData.append(magasin)
//self.pickerData = [(self.produits[0].magasin)]
}
print(self.pickerData)
dispatch_async(dispatch_get_main_queue()) {
self.picker1.reloadInputViews()
// print(self.produits.count)
}
}
}
} catch {
print("JSON serialization failed", error)
}
} else if let connectionError = error {
print("connection error", connectionError)
}
}
task.resume()
//print(produits.count)
//pickerData = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "autre"]
//print(self.pickerData)
self.picker1.delegate = self
self.picker1.dataSource = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// The number of columns of data
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
// The number of rows of data
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return self.pickerData.count
}
// The data to return for the row and component (column) that's being passed in
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return self.pickerData[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerData[row] == "autre"
{
//print(row)
NomMAG.alpha = 1
}
else
{
//print(row.description)
NomMAG.alpha = 0
}
}
I want to get my PickerView full with the data i gained from the JsonParsing and the PickerData Array is null outside the block of code of the Json
Connect delegate and dataSource of the picker view in Interface Builder and replace viewDidLoad with
var pickerData = [String]()
override func viewDidLoad() {
super.viewDidLoad()
let str = "http://vps43623.ovh.net/yamoinscher/api/getAllMag"
let url = NSURL(string: str)!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
if let urlContent = data {
do {
let jsonObject = try NSJSONSerialization.JSONObjectWithData(urlContent, options: [])
if let jsonResult = jsonObject as? [String:AnyObject],
magasin = jsonResult["magasin"] as? [[String:String]] {
// filter valid items, map them to an array and filter empty strings
self.pickerData = magasin.filter { $0["libelle"] != nil }.map { $0["libelle"]! }.filter { !$0.isEmpty}
}
dispatch_async(dispatch_get_main_queue()) {
self.picker1.reloadAllComponents()
}
} catch {
print("JSON serialization failed", error)
}
} else if let connectionError = error {
print("connection error", connectionError)
}
}
task.resume()
}
You have to add the NomMAG line