Programmatically implementing a UIPickerView when user taps UITextfield - ios

I am currently working on a small project and i have a viewController that has 4 textFields which 3 work ok. They take String objects. However, the 4th textField is supposed to bring up a UIPickerView with 4 selectable items.
So far this is what i have in my controller that implements this:
#IBOutlet var pickerTextfield: UITextField!
#IBOutlet var itemPicker: UIPickerView! = UIPickerView()
The pickerTextfield is the UITextField object that is the 4th field.
The itemPicker is an unlinked UIPickerView that i want to create programatically.
Right below these properties, i have an array of items for the UIPickerView object:
var seasonalItems = ["Spring", "Summer", "Fall", "Winter"]
In my viewDidLoad method i have this as follow:
itemPicker.hidden = true;
pickerTextfield.text = seasonalItems[0]
pickerTextfield.delegate = self
And the rest of the implementation:
// Below these lines is the implementation of the Picker
func numberOfComponentsInPickerView(pickerView: UIPickerView!) -> Int{
return 1
}
// returns the # of rows in each component..
func pickerView(pickerView: UIPickerView!, numberOfRowsInComponent component: Int) -> Int{
return seasonalItems.count
}
func pickerView(pickerView: UIPickerView!, titleForRow row: Int, forComponent component: Int) -> String! {
return seasonalItems[row]
}
func pickerView(pickerView: UIPickerView!, didSelectRow row: Int, inComponent component: Int)
{
pickerTextfield.text = seasonalItems[row]
itemPicker.hidden = true;
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
itemPicker.hidden = false
return false
}
So the end result from this is when i tap the pickerTextfield object in the app, it shows the first item of the array (Spring) but in text within the UITextField object but it does not show the UIPickerView object with the other selectable items where i could select one and then hide it when selected.
My question is, where or what am i doing wrong here? i been trying to figure this out on my own but i do not seem to get good clear examples with Swift and storyboards. I much rather not drag a UIPickerView in the storyboard but rather the way i attempted to implement. Thanks

You can give UIPickerView as inputView for your TextField in which you want to show picker view.
You also do not need to initially hide picker view in this case.
pickerTextfield.inputView = itemPicker
When you use UIPickerView as inputView of any UITextField then when you tap on the TextField instead of default keypad PickerView will show.

Related

Drop-down style UIPickerView?

I was wondering how to get a UIPickerView to slide up from the bottom of the screen after tapping on a drop-down style button. Like in the image below:
I've run into this type of picker views a lot in the apps that I use regularly, so honestly I was expecting to easily find this picker view by setting the UIPickerView's style property, or something like that. Is this even a UIPickerView or do I have to create this kind of view manually?
One way of doing this is to have a normal UITextField and then assign a UIPickerView as the inputView of that textfield. That way, instead of a keyboard appearing when you tap your textfield, you get your pickerview.
Example
First declare a normal UIPickerView instance:
let yourPicker = UIPickerView()
and an outlet to a UITextField:
#IBOutlet weak var yourTextField: UITextField!
In your viewDidLoad you tie the elements together
yourPicker.delegate = self
yourPicker.dataSource = self
yourTextField.inputView = yourPicker
And then you need to implement the required methods of UIPickerViewDelegate and UIPickerViewDataSource
Finally. In pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) you update the value of your textfield:
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
yourTextField.text = yourDataArrayUsedInThePicker[row]
}
Read more
Description of inputView
https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/InputViews/InputViews.html
A way better explaination than mine:
Show UIPickerView text field is selected, then hide after selected
Hope that helps you.

Picker View Swift

I have a picker view that needs to be presented when UIButton is pressed. The text of the UIButton will change to the text of selected row. But how do I initiate the picker view for a button?
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
picker.dataSource = self
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return CountryData.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
CountryButton.setTitle(CountryData[row], for: .normal)
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return CountryData[row]
}
#IBAction func Country(_ sender: AnyObject) {
CountryButton.inputView == picker
}
This won't work
Note: when you set the action method, be sure to set the sender to the type of control that's invoking the action, the UIButton or the UIPickerView or whatever. Don't leave it as AnyObject.
It's not completely clear to me what you're trying to do. You say that the picker view needs to change when you press a button, then you say that the text of the button needs to change to the row selected in the picker view.
Are you trying to get the text of the button to change when you select something in the picker view? Or are you trying to instantiate a new picker view when you press the button?
If you're trying to change the text of the button when you select a row in the picker view, then you want to add an onChanged() action method for the picker view and change the button's text in that method.
#IBAction func pickerChanged(_ sender: UIPickerView) {
button.setTitle("New text", for: UIControlState)
}
An easy way to present a new picker view when a button is pressed is to put the picker view in a stack view and set its hide property. Then the button's onPress() method can unhide the picker view in the stack view.
#IBAction func onPress(_ sender: UIButton) {
if weWannaShowthePicker {
pickerStack.arrangedSubviews[pickerPosition].isHidden = false
} else { // hide it
pickerStack.arrangedSubviews[pickerPosition].isHidden = true
}
}

Get UITextField from UIPickerView when using it as input view

Is there a possibility to get UITextField from UIPickerView? I set my UIPickerView as inputView for text filed. I have few text fields on the screen and I want to simple get current text field that shown picker view.
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
// something like let textField = pickerView.requestedTextField
}
Is there any way to do it?
If you have multiple textField that show pickerView then create one more instance of textField in your viewController like this and use this object inside textFieldDidBeginEditing and assign the reference of that textField to that tempTextField.
var selectedTextField: UITextField = UITextField()
func textFieldDidBeginEditing(textField: UITextField!) {
self.selectedTextField = textField
}
Now in didSelectRow method of PickerView use this textField o know the current editing field.
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if self.selectedTextField == countryField {
//Set text for countryField
}
else self.selectedTextField == stateField {
//Set text for stateField
}
}
Note: For example I have used countryField and stateField you can use textField for that you want to set text.
Set same tag to your pickerview and textfield both.
now you can get your tag in didSelectRow like,
let myTag = pickerView.tag
and then from myTag you can get your textfield something like,
let myTextField = self.view.viewWithTag(myTag) as! UITextField
As user Lion rightly pointed out in his answer, you can get the corresponding UITextField by giving both the pickerView and textField a tag. However, the issue with giving them the same tag is that viewWithTag may return the UIPickerView itself, depending on the order of the subviews.
As this is unreliable, a better solution would be to give the UITextField the negative of the tag given to the UIPickerView (eg. 1 and -1). To get the UITextView, you would do something like this in your method, once you have assigned your picker views and text views opposite tags:
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let textField = view.viewWithTag(-pickerView.tag) as! UITextField
//Use textField
}

Selecting first row in UIPickerView issue

I've a many textfield and a pickerView with toolBar and it has a done button. My issue is I can't select the first row from the picker. While I have debugged in the didSelectRow but it won't run inside it. So please where would be my issue?
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
var value = currentPickerArray[row]
textFieldOutletArray[currentTag].text = value
}
Just replace didSelect method in your sample code like as bellowed. it will working fine.
#IBAction func doneBtn(sender: AnyObject) {
var row = pickerView.selectedRowInComponent(0);
NSLog("value L %d", row)
pickerView(pickerView, didSelectRow: row, inComponent:0)
}
Hope this help you.
In the titleForRow function add this line of code. It shows first row selected:
textField.text = pickerArray.objectAtIndex(row).objectForKey("Name") as? String

How to build a variable from another variable

I hope the title makes some sense but what I am trying to do is to set a field value to the item selected variable from my dataPicker. I have been able to make this work when there is only one field to set but my project will have multiple fields on each view that will call data from the dataPicker based on what field it is. I hope that is clear. Maybe as you look at the code it will.
I have set up a test project to limit things to this issue only. So my variable to tell the view what array to populate in the dataPicker is either season or sport. the field that will receive the data from the season/sport array is enterSeason and enterSport. When the picker has returned a value from season, I want to combine it with enter to create the var enterSeason to set that == itemSelected. This language is very new to me so I am trying the only way I have used before to combine text and variables in one value. It is obviously not working. Help is appreciated.
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UIGestureRecognizerDelegate {
#IBOutlet var enterSeason: UITextField!
#IBOutlet var enterSport: UITextField!
var dataPickerView = UIPickerView()
var season = ["2013", "2014", "2015"] //multi-season
//var season = ["2015"] //single-season
var sport = ["Baeball", "Football", "Basketball", "Hokey"]
var activeField = []
override func viewDidLoad() {
super.viewDidLoad()
enterSeason.inputView = dataPickerView
dataPickerView.delegate = self
dataPickerView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return activeField.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return activeField[row] as! String
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
var itemSelected = activeField[row] as! String
self.enter"\activeField".text = itemSelected
}
}
EDIT : How do you show and hide the picker? Your code anly shows variable declarations and the delegate methods... answers could vary accordingly..
Since you show the picker as text field's input view, set UITextFieldDelegate for each of these text fields .. and in the textFieldDidBeginEditing check which field becomes active with simple if else
func textFieldDidBeginEditing(textField: UITextField) {
if textField === enterSeason {
activeField = season
}
else if textField === enterSport {
activeField = sport
}
}
And in the picker selector, set value of the relevant text field as per current activeField object
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if activeField === season {
enterSeason.text = season[row] as! String
}
else if activeField === sport {
enterSeason.text = sport[row] as! String
}
}
Setting the delegate for your text fields in storboard/xib :
P.S.
- Rename activeField to activeDataArray or somethiong more appropriate
EDIT 2 : As you mentioned, second approach i have mentioned below is not suitable for you because there are too many of these fields i am still keeping it as part of the answer as it may help someone else
But what you are trying to achieve is very simple and approach is too convoluted / weird. So heres another way you can implement the whole thing..
The easiest (but still probably not the best) way is to have two instances of the UIPickerView for each field. you can directly check pickerView == seasonPickerView OR pickerView == sportPickerViewin an if else block and do the conditional programming and you wont need the activeField variable..

Resources